drmmode_display.c revision 446f62d6
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 511446f62d6Smrgdrmmode_crtc_scanout_free(xf86CrtcPtr crtc) 51218781e08Smrg{ 513446f62d6Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 514446f62d6Smrg 515446f62d6Smrg if (drmmode_crtc->scanout_update_pending) { 516446f62d6Smrg radeon_drm_wait_pending_flip(crtc); 517446f62d6Smrg radeon_drm_abort_entry(drmmode_crtc->scanout_update_pending); 518446f62d6Smrg drmmode_crtc->scanout_update_pending = 0; 519446f62d6Smrg radeon_drm_queue_handle_deferred(crtc); 520446f62d6Smrg } 521446f62d6Smrg 5228bf5c682Smrg drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 5238bf5c682Smrg &drmmode_crtc->scanout[0]); 5248bf5c682Smrg drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 5258bf5c682Smrg &drmmode_crtc->scanout[1]); 52618781e08Smrg 5278bf5c682Smrg if (drmmode_crtc->scanout_damage) 52818781e08Smrg DamageDestroy(drmmode_crtc->scanout_damage); 52918781e08Smrg} 53018781e08Smrg 5318bf5c682SmrgPixmapPtr 5323ed65abbSmrgdrmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout, 5333ed65abbSmrg int width, int height) 53418781e08Smrg{ 53518781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 53618781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 53718781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 53818781e08Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 53918781e08Smrg struct radeon_surface surface; 54018781e08Smrg uint32_t tiling = RADEON_CREATE_PIXMAP_TILING_MACRO; 54118781e08Smrg int pitch; 54218781e08Smrg 5433ed65abbSmrg if (scanout->pixmap) { 54418781e08Smrg if (scanout->width == width && scanout->height == height) 5453ed65abbSmrg return scanout->pixmap; 54618781e08Smrg 54718781e08Smrg drmmode_crtc_scanout_destroy(drmmode, scanout); 54818781e08Smrg } 54918781e08Smrg 55018781e08Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) 55118781e08Smrg tiling |= RADEON_CREATE_PIXMAP_TILING_MICRO; 55218781e08Smrg scanout->bo = radeon_alloc_pixmap_bo(pScrn, width, height, pScrn->depth, 55318781e08Smrg tiling, pScrn->bitsPerPixel, 55418781e08Smrg &pitch, &surface, &tiling); 5558bf5c682Smrg if (!scanout->bo) { 5568bf5c682Smrg ErrorF("failed to create CRTC scanout BO\n"); 5578bf5c682Smrg return NULL; 55818781e08Smrg } 55918781e08Smrg 56018781e08Smrg scanout->pixmap = drmmode_create_bo_pixmap(pScrn, 56118781e08Smrg width, height, 56218781e08Smrg pScrn->depth, 56318781e08Smrg pScrn->bitsPerPixel, 56439413783Smrg pitch, scanout->bo); 5658bf5c682Smrg if (!scanout->pixmap) { 5668bf5c682Smrg ErrorF("failed to create CRTC scanout pixmap\n"); 5678bf5c682Smrg goto error; 5688bf5c682Smrg } 5698bf5c682Smrg 5708bf5c682Smrg if (radeon_pixmap_get_fb(scanout->pixmap)) { 5713ed65abbSmrg scanout->width = width; 5723ed65abbSmrg scanout->height = height; 5733ed65abbSmrg } else { 5748bf5c682Smrg ErrorF("failed to create CRTC scanout FB\n"); 5758bf5c682Smrgerror: 5763ed65abbSmrg drmmode_crtc_scanout_destroy(drmmode, scanout); 5773ed65abbSmrg } 57818781e08Smrg 57918781e08Smrg return scanout->pixmap; 58018781e08Smrg} 58118781e08Smrg 58218781e08Smrgstatic void 58318781e08Smrgradeon_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure) 58418781e08Smrg{ 5858bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc = closure; 5868bf5c682Smrg 5878bf5c682Smrg if (drmmode_crtc->ignore_damage) { 5888bf5c682Smrg RegionEmpty(&damage->damage); 5898bf5c682Smrg drmmode_crtc->ignore_damage = FALSE; 5908bf5c682Smrg return; 5918bf5c682Smrg } 5928bf5c682Smrg 59318781e08Smrg /* Only keep track of the extents */ 59418781e08Smrg RegionUninit(&damage->damage); 59518781e08Smrg damage->damage.data = NULL; 59618781e08Smrg} 59718781e08Smrg 5988bf5c682Smrgstatic void 5998bf5c682Smrgdrmmode_screen_damage_destroy(DamagePtr damage, void *closure) 6008bf5c682Smrg{ 6018bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc = closure; 6028bf5c682Smrg 6038bf5c682Smrg drmmode_crtc->scanout_damage = NULL; 6048bf5c682Smrg RegionUninit(&drmmode_crtc->scanout_last_region); 6058bf5c682Smrg} 6068bf5c682Smrg 60718781e08Smrgstatic Bool 60818781e08Smrgdrmmode_can_use_hw_cursor(xf86CrtcPtr crtc) 60918781e08Smrg{ 61018781e08Smrg RADEONInfoPtr info = RADEONPTR(crtc->scrn); 61118781e08Smrg 61218781e08Smrg /* Check for Option "SWcursor" */ 61318781e08Smrg if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) 61418781e08Smrg return FALSE; 61518781e08Smrg 61618781e08Smrg /* Fall back to SW cursor if the CRTC is transformed */ 61718781e08Smrg if (crtc->transformPresent) 61818781e08Smrg return FALSE; 6190d16fef4Smrg 6208bf5c682Smrg#if XF86_CRTC_VERSION < 7 62118781e08Smrg /* Xorg doesn't correctly handle cursor position transform in the 62218781e08Smrg * rotation case 62318781e08Smrg */ 62418781e08Smrg if (crtc->driverIsPerformingTransform && 62518781e08Smrg (crtc->rotation & 0xf) != RR_Rotate_0) 62618781e08Smrg return FALSE; 62718781e08Smrg#endif 62818781e08Smrg 62918781e08Smrg /* HW cursor not supported with RandR 1.4 multihead up to 1.18.99.901 */ 63018781e08Smrg if (xorgGetVersion() <= XORG_VERSION_NUMERIC(1,18,99,901,0) && 63118781e08Smrg !xorg_list_is_empty(&crtc->scrn->pScreen->pixmap_dirty_list)) 63218781e08Smrg return FALSE; 63318781e08Smrg 63418781e08Smrg return TRUE; 63518781e08Smrg} 63618781e08Smrg 6373ed65abbSmrgstatic void 6383ed65abbSmrgdrmmode_crtc_update_tear_free(xf86CrtcPtr crtc) 6393ed65abbSmrg{ 6403ed65abbSmrg RADEONInfoPtr info = RADEONPTR(crtc->scrn); 6413ed65abbSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 6423ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 6433ed65abbSmrg int i; 6443ed65abbSmrg 6453ed65abbSmrg drmmode_crtc->tear_free = FALSE; 6463ed65abbSmrg 6473ed65abbSmrg for (i = 0; i < xf86_config->num_output; i++) { 6483ed65abbSmrg xf86OutputPtr output = xf86_config->output[i]; 6493ed65abbSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 6503ed65abbSmrg 6513ed65abbSmrg if (output->crtc != crtc) 6523ed65abbSmrg continue; 6533ed65abbSmrg 6543ed65abbSmrg if (drmmode_output->tear_free == 1 || 6553ed65abbSmrg (drmmode_output->tear_free == 2 && 6568bf5c682Smrg (crtc->scrn->pScreen->isGPU || 6573ed65abbSmrg info->shadow_primary || 6583ed65abbSmrg crtc->transformPresent || crtc->rotation != RR_Rotate_0))) { 6593ed65abbSmrg drmmode_crtc->tear_free = TRUE; 6603ed65abbSmrg return; 6613ed65abbSmrg } 6623ed65abbSmrg } 6633ed65abbSmrg} 6643ed65abbSmrg 6653ed65abbSmrg#if XF86_CRTC_VERSION < 7 6663ed65abbSmrg#define XF86DriverTransformOutput TRUE 6673ed65abbSmrg#define XF86DriverTransformNone FALSE 6683ed65abbSmrg#endif 6693ed65abbSmrg 67018781e08Smrgstatic Bool 67118781e08Smrgdrmmode_handle_transform(xf86CrtcPtr crtc) 67218781e08Smrg{ 67318781e08Smrg Bool ret; 67418781e08Smrg 6758bf5c682Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 67639413783Smrg crtc->driverIsPerformingTransform = XF86DriverTransformOutput; 6778bf5c682Smrg#else 6788bf5c682Smrg crtc->driverIsPerformingTransform = !crtc->transformPresent && 6798bf5c682Smrg (crtc->rotation & 0xf) == RR_Rotate_0; 6808bf5c682Smrg#endif 68118781e08Smrg 68218781e08Smrg ret = xf86CrtcRotate(crtc); 68318781e08Smrg 68418781e08Smrg crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use; 68518781e08Smrg 68618781e08Smrg return ret; 6870d16fef4Smrg} 6880d16fef4Smrg 6893ed65abbSmrg 6903ed65abbSmrgstatic void 6913ed65abbSmrgdrmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, 6928bf5c682Smrg unsigned scanout_id, struct drmmode_fb **fb, 6938bf5c682Smrg int *x, int *y) 6943ed65abbSmrg{ 6953ed65abbSmrg ScrnInfoPtr scrn = crtc->scrn; 6963ed65abbSmrg ScreenPtr screen = scrn->pScreen; 6973ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 6983ed65abbSmrg 6993ed65abbSmrg if (drmmode_crtc->tear_free && 7003ed65abbSmrg !drmmode_crtc->scanout[1].pixmap) { 7013ed65abbSmrg RegionPtr region; 7023ed65abbSmrg BoxPtr box; 7033ed65abbSmrg 7043ed65abbSmrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 7053ed65abbSmrg mode->HDisplay, 7063ed65abbSmrg mode->VDisplay); 7073ed65abbSmrg region = &drmmode_crtc->scanout_last_region; 7083ed65abbSmrg RegionUninit(region); 7093ed65abbSmrg region->data = NULL; 7103ed65abbSmrg box = RegionExtents(region); 7113ed65abbSmrg box->x1 = crtc->x; 7123ed65abbSmrg box->y1 = crtc->y; 7133ed65abbSmrg box->x2 = crtc->x + mode->HDisplay; 7143ed65abbSmrg box->y2 = crtc->y + mode->VDisplay; 7153ed65abbSmrg } 7163ed65abbSmrg 7173ed65abbSmrg if (scanout_id != drmmode_crtc->scanout_id) { 7183ed65abbSmrg PixmapDirtyUpdatePtr dirty = NULL; 7193ed65abbSmrg 7203ed65abbSmrg xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, 7213ed65abbSmrg ent) { 7228bf5c682Smrg if (radeon_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) { 7233ed65abbSmrg dirty->slave_dst = 7243ed65abbSmrg drmmode_crtc->scanout[scanout_id].pixmap; 7253ed65abbSmrg break; 7263ed65abbSmrg } 7273ed65abbSmrg } 7283ed65abbSmrg 7293ed65abbSmrg if (!drmmode_crtc->tear_free) { 7303ed65abbSmrg GCPtr gc = GetScratchGC(scrn->depth, screen); 7313ed65abbSmrg 7323ed65abbSmrg ValidateGC(&drmmode_crtc->scanout[0].pixmap->drawable, gc); 7333ed65abbSmrg gc->ops->CopyArea(&drmmode_crtc->scanout[1].pixmap->drawable, 7343ed65abbSmrg &drmmode_crtc->scanout[0].pixmap->drawable, 7353ed65abbSmrg gc, 0, 0, mode->HDisplay, mode->VDisplay, 7363ed65abbSmrg 0, 0); 7373ed65abbSmrg FreeScratchGC(gc); 73839413783Smrg radeon_finish(scrn, drmmode_crtc->scanout[0].bo); 7393ed65abbSmrg } 7403ed65abbSmrg } 7413ed65abbSmrg 7428bf5c682Smrg *fb = radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap); 7433ed65abbSmrg *x = *y = 0; 7443ed65abbSmrg drmmode_crtc->scanout_id = scanout_id; 7453ed65abbSmrg} 7463ed65abbSmrg 7473ed65abbSmrg 7483ed65abbSmrgstatic void 7493ed65abbSmrgdrmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, 7508bf5c682Smrg unsigned scanout_id, struct drmmode_fb **fb, int *x, 7518bf5c682Smrg int *y) 7523ed65abbSmrg{ 7533ed65abbSmrg ScrnInfoPtr scrn = crtc->scrn; 7543ed65abbSmrg ScreenPtr screen = scrn->pScreen; 7553ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 7563ed65abbSmrg 7578bf5c682Smrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[scanout_id], 7583ed65abbSmrg mode->HDisplay, mode->VDisplay); 7593ed65abbSmrg if (drmmode_crtc->tear_free) { 7608bf5c682Smrg drmmode_crtc_scanout_create(crtc, 7618bf5c682Smrg &drmmode_crtc->scanout[scanout_id ^ 1], 7623ed65abbSmrg mode->HDisplay, mode->VDisplay); 7633ed65abbSmrg } 7643ed65abbSmrg 7658bf5c682Smrg if (drmmode_crtc->scanout[scanout_id].pixmap && 7668bf5c682Smrg (!drmmode_crtc->tear_free || 7678bf5c682Smrg drmmode_crtc->scanout[scanout_id ^ 1].pixmap)) { 76839413783Smrg BoxRec extents = { .x1 = 0, .y1 = 0, 76939413783Smrg .x2 = scrn->virtualX, .y2 = scrn->virtualY }; 7703ed65abbSmrg 7713ed65abbSmrg if (!drmmode_crtc->scanout_damage) { 7723ed65abbSmrg drmmode_crtc->scanout_damage = 7733ed65abbSmrg DamageCreate(radeon_screen_damage_report, 7748bf5c682Smrg drmmode_screen_damage_destroy, 7758bf5c682Smrg DamageReportRawRegion, 7768bf5c682Smrg TRUE, screen, drmmode_crtc); 7778bf5c682Smrg DamageRegister(&screen->root->drawable, 7783ed65abbSmrg drmmode_crtc->scanout_damage); 7793ed65abbSmrg } 7803ed65abbSmrg 7818bf5c682Smrg *fb = radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap); 7823ed65abbSmrg *x = *y = 0; 7833ed65abbSmrg 784446f62d6Smrg if (radeon_scanout_do_update(crtc, scanout_id, 785446f62d6Smrg screen->GetWindowPixmap(screen->root), 786446f62d6Smrg extents)) { 787446f62d6Smrg RegionEmpty(DamageRegion(drmmode_crtc->scanout_damage)); 788446f62d6Smrg radeon_finish(scrn, drmmode_crtc->scanout[scanout_id].bo); 789446f62d6Smrg 790446f62d6Smrg if (!drmmode_crtc->flip_pending) { 791446f62d6Smrg radeon_drm_abort_entry(drmmode_crtc-> 792446f62d6Smrg scanout_update_pending); 793446f62d6Smrg } 794446f62d6Smrg } 7953ed65abbSmrg } 7963ed65abbSmrg} 7973ed65abbSmrg 7988bf5c682Smrgstatic void 7998bf5c682Smrgdrmmode_crtc_gamma_do_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 8008bf5c682Smrg uint16_t *blue, int size) 8018bf5c682Smrg{ 8028bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 8038bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 8048bf5c682Smrg 8058bf5c682Smrg drmModeCrtcSetGamma(pRADEONEnt->fd, 8068bf5c682Smrg drmmode_crtc->mode_crtc->crtc_id, size, red, green, 8078bf5c682Smrg blue); 8088bf5c682Smrg} 8098bf5c682Smrg 8108bf5c682SmrgBool 8118bf5c682Smrgdrmmode_set_mode(xf86CrtcPtr crtc, struct drmmode_fb *fb, DisplayModePtr mode, 8128bf5c682Smrg int x, int y) 8138bf5c682Smrg{ 8148bf5c682Smrg ScrnInfoPtr scrn = crtc->scrn; 8158bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 8168bf5c682Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 8178bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 8188bf5c682Smrg uint32_t *output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); 8198bf5c682Smrg int output_count = 0; 8208bf5c682Smrg drmModeModeInfo kmode; 8218bf5c682Smrg Bool ret; 8228bf5c682Smrg int i; 8238bf5c682Smrg 8248bf5c682Smrg if (!output_ids) 8258bf5c682Smrg return FALSE; 8268bf5c682Smrg 8278bf5c682Smrg for (i = 0; i < xf86_config->num_output; i++) { 8288bf5c682Smrg xf86OutputPtr output = xf86_config->output[i]; 8298bf5c682Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 8308bf5c682Smrg 8318bf5c682Smrg if (output->crtc != crtc) 8328bf5c682Smrg continue; 8338bf5c682Smrg 8348bf5c682Smrg output_ids[output_count] = drmmode_output->mode_output->connector_id; 8358bf5c682Smrg output_count++; 8368bf5c682Smrg } 8378bf5c682Smrg 8388bf5c682Smrg drmmode_ConvertToKMode(scrn, &kmode, mode); 8398bf5c682Smrg 8408bf5c682Smrg ret = drmModeSetCrtc(pRADEONEnt->fd, 8418bf5c682Smrg drmmode_crtc->mode_crtc->crtc_id, 8428bf5c682Smrg fb->handle, x, y, output_ids, 8438bf5c682Smrg output_count, &kmode) == 0; 8448bf5c682Smrg 8458bf5c682Smrg if (ret) { 8468bf5c682Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, fb); 8478bf5c682Smrg } else { 8488bf5c682Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 8498bf5c682Smrg "failed to set mode: %s\n", strerror(errno)); 8508bf5c682Smrg } 8518bf5c682Smrg 8528bf5c682Smrg free(output_ids); 8538bf5c682Smrg return ret; 8548bf5c682Smrg} 8558bf5c682Smrg 856de2362d3Smrgstatic Bool 857de2362d3Smrgdrmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 858de2362d3Smrg Rotation rotation, int x, int y) 859de2362d3Smrg{ 860de2362d3Smrg ScrnInfoPtr pScrn = crtc->scrn; 86118781e08Smrg ScreenPtr pScreen = pScrn->pScreen; 862de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 8638bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 864de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 865de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 866446f62d6Smrg Bool handle_deferred = FALSE; 8673ed65abbSmrg unsigned scanout_id = 0; 868de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 869de2362d3Smrg int saved_x, saved_y; 870de2362d3Smrg Rotation saved_rotation; 871de2362d3Smrg DisplayModeRec saved_mode; 87218781e08Smrg Bool ret = FALSE; 873de2362d3Smrg int i; 8748bf5c682Smrg struct drmmode_fb *fb = NULL; 8758bf5c682Smrg 8768bf5c682Smrg /* The root window contents may be undefined before the WindowExposures 8778bf5c682Smrg * hook is called for it, so bail if we get here before that 8788bf5c682Smrg */ 8798bf5c682Smrg if (pScreen->WindowExposures == RADEONWindowExposures_oneshot) 8808bf5c682Smrg return FALSE; 881de2362d3Smrg 882de2362d3Smrg saved_mode = crtc->mode; 883de2362d3Smrg saved_x = crtc->x; 884de2362d3Smrg saved_y = crtc->y; 885de2362d3Smrg saved_rotation = crtc->rotation; 886de2362d3Smrg 887de2362d3Smrg if (mode) { 888de2362d3Smrg crtc->mode = *mode; 889de2362d3Smrg crtc->x = x; 890de2362d3Smrg crtc->y = y; 891de2362d3Smrg crtc->rotation = rotation; 892de2362d3Smrg 89318781e08Smrg if (!drmmode_handle_transform(crtc)) 894de2362d3Smrg goto done; 89518781e08Smrg 8963ed65abbSmrg drmmode_crtc_update_tear_free(crtc); 8973ed65abbSmrg if (drmmode_crtc->tear_free) 8983ed65abbSmrg scanout_id = drmmode_crtc->scanout_id; 89939413783Smrg else 90039413783Smrg drmmode_crtc->scanout_id = 0; 901de2362d3Smrg 9028bf5c682Smrg if (drmmode_crtc->prime_scanout_pixmap) { 9033ed65abbSmrg drmmode_crtc_prime_scanout_update(crtc, mode, scanout_id, 9048bf5c682Smrg &fb, &x, &y); 9058bf5c682Smrg } else if (drmmode_crtc->rotate.pixmap) { 9068bf5c682Smrg fb = radeon_pixmap_get_fb(drmmode_crtc->rotate.pixmap); 90718781e08Smrg x = y = 0; 90818781e08Smrg 9098bf5c682Smrg } else if (!pScreen->isGPU && 9103ed65abbSmrg (drmmode_crtc->tear_free || 91118781e08Smrg crtc->driverIsPerformingTransform || 91218781e08Smrg info->shadow_primary)) { 9133ed65abbSmrg drmmode_crtc_scanout_update(crtc, mode, scanout_id, 9148bf5c682Smrg &fb, &x, &y); 915de2362d3Smrg } 91618781e08Smrg 9178bf5c682Smrg if (!fb) 9188bf5c682Smrg fb = radeon_pixmap_get_fb(pScreen->GetWindowPixmap(pScreen->root)); 9198bf5c682Smrg if (!fb) { 9208bf5c682Smrg fb = radeon_fb_create(pScrn, pRADEONEnt->fd, 9218bf5c682Smrg pScrn->virtualX, pScrn->virtualY, 9228bf5c682Smrg pScrn->displayWidth * info->pixel_bytes, 92339413783Smrg info->front_buffer->bo.radeon->handle); 9248bf5c682Smrg /* Prevent refcnt of ad-hoc FBs from reaching 2 */ 9258bf5c682Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, NULL); 9268bf5c682Smrg drmmode_crtc->fb = fb; 9278bf5c682Smrg } 9288bf5c682Smrg if (!fb) { 9298bf5c682Smrg ErrorF("failed to add FB for modeset\n"); 9308bf5c682Smrg goto done; 93118781e08Smrg } 93218781e08Smrg 93339413783Smrg radeon_drm_wait_pending_flip(crtc); 934446f62d6Smrg handle_deferred = TRUE; 9358bf5c682Smrg 9368bf5c682Smrg if (!drmmode_set_mode(crtc, fb, mode, x, y)) 93718781e08Smrg goto done; 9388bf5c682Smrg 9398bf5c682Smrg ret = TRUE; 940de2362d3Smrg 94118781e08Smrg if (pScreen) 94218781e08Smrg xf86CrtcSetScreenSubpixelOrder(pScreen); 94318781e08Smrg 94418781e08Smrg drmmode_crtc->need_modeset = FALSE; 94518781e08Smrg 946de2362d3Smrg /* go through all the outputs and force DPMS them back on? */ 947de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 948de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 949de2362d3Smrg 950de2362d3Smrg if (output->crtc != crtc) 951de2362d3Smrg continue; 952de2362d3Smrg 953de2362d3Smrg output->funcs->dpms(output, DPMSModeOn); 954de2362d3Smrg } 955de2362d3Smrg } 956de2362d3Smrg 95718781e08Smrg /* Compute index of this CRTC into xf86_config->crtc */ 95818781e08Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 95918781e08Smrg if (xf86_config->crtc[i] != crtc) 96018781e08Smrg continue; 96118781e08Smrg 96218781e08Smrg if (!crtc->enabled || drmmode_can_use_hw_cursor(crtc)) 96318781e08Smrg info->hwcursor_disabled &= ~(1 << i); 96418781e08Smrg else 96518781e08Smrg info->hwcursor_disabled |= 1 << i; 96618781e08Smrg 96718781e08Smrg break; 96818781e08Smrg } 96918781e08Smrg 97018781e08Smrg#ifndef HAVE_XF86_CURSOR_RESET_CURSOR 97118781e08Smrg if (!info->hwcursor_disabled) 97218781e08Smrg xf86_reload_cursors(pScreen); 97318781e08Smrg#endif 974de2362d3Smrg 975de2362d3Smrgdone: 976de2362d3Smrg if (!ret) { 977de2362d3Smrg crtc->x = saved_x; 978de2362d3Smrg crtc->y = saved_y; 979de2362d3Smrg crtc->rotation = saved_rotation; 980de2362d3Smrg crtc->mode = saved_mode; 98118781e08Smrg } else { 9827821949aSmrg crtc->active = TRUE; 98318781e08Smrg 9848bf5c682Smrg if (drmmode_crtc->scanout[scanout_id].pixmap && 9858bf5c682Smrg fb != radeon_pixmap_get_fb(drmmode_crtc-> 98639413783Smrg scanout[scanout_id].pixmap)) { 987446f62d6Smrg drmmode_crtc_scanout_free(crtc); 98839413783Smrg } else if (!drmmode_crtc->tear_free) { 9893ed65abbSmrg drmmode_crtc_scanout_destroy(drmmode, 9903ed65abbSmrg &drmmode_crtc->scanout[1]); 9913ed65abbSmrg } 99218781e08Smrg } 99318781e08Smrg 994446f62d6Smrg if (handle_deferred) 995446f62d6Smrg radeon_drm_queue_handle_deferred(crtc); 996446f62d6Smrg 997de2362d3Smrg return ret; 998de2362d3Smrg} 999de2362d3Smrg 1000de2362d3Smrgstatic void 1001de2362d3Smrgdrmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg) 1002de2362d3Smrg{ 1003de2362d3Smrg 1004de2362d3Smrg} 1005de2362d3Smrg 1006de2362d3Smrgstatic void 1007de2362d3Smrgdrmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y) 1008de2362d3Smrg{ 1009de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 10108bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 1011de2362d3Smrg 10128bf5c682Smrg#if XF86_CRTC_VERSION < 7 101318781e08Smrg if (crtc->driverIsPerformingTransform) { 101418781e08Smrg x += crtc->x; 101518781e08Smrg y += crtc->y; 101618781e08Smrg xf86CrtcTransformCursorPos(crtc, &x, &y); 101718781e08Smrg } 101818781e08Smrg#endif 101918781e08Smrg 1020446f62d6Smrg drmmode_crtc->cursor_x = x; 1021446f62d6Smrg drmmode_crtc->cursor_y = y; 1022446f62d6Smrg 10238bf5c682Smrg drmModeMoveCursor(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); 1024de2362d3Smrg} 1025de2362d3Smrg 10268bf5c682Smrg#if XF86_CRTC_VERSION < 7 102718781e08Smrg 102818781e08Smrgstatic int 102918781e08Smrgdrmmode_cursor_src_offset(Rotation rotation, int width, int height, 103018781e08Smrg int x_dst, int y_dst) 103118781e08Smrg{ 103218781e08Smrg int t; 103318781e08Smrg 103418781e08Smrg switch (rotation & 0xf) { 103518781e08Smrg case RR_Rotate_90: 103618781e08Smrg t = x_dst; 103718781e08Smrg x_dst = height - y_dst - 1; 103818781e08Smrg y_dst = t; 103918781e08Smrg break; 104018781e08Smrg case RR_Rotate_180: 104118781e08Smrg x_dst = width - x_dst - 1; 104218781e08Smrg y_dst = height - y_dst - 1; 104318781e08Smrg break; 104418781e08Smrg case RR_Rotate_270: 104518781e08Smrg t = x_dst; 104618781e08Smrg x_dst = y_dst; 104718781e08Smrg y_dst = width - t - 1; 104818781e08Smrg break; 104918781e08Smrg } 105018781e08Smrg 105118781e08Smrg if (rotation & RR_Reflect_X) 105218781e08Smrg x_dst = width - x_dst - 1; 105318781e08Smrg if (rotation & RR_Reflect_Y) 105418781e08Smrg y_dst = height - y_dst - 1; 105518781e08Smrg 105618781e08Smrg return y_dst * height + x_dst; 105718781e08Smrg} 105818781e08Smrg 105918781e08Smrg#endif 106018781e08Smrg 1061446f62d6Smrgstatic Bool 1062446f62d6Smrgdrmmode_cursor_pixel(xf86CrtcPtr crtc, uint32_t *argb, Bool *premultiplied, 1063446f62d6Smrg Bool *apply_gamma) 10648bf5c682Smrg{ 1065446f62d6Smrg uint32_t alpha = *argb >> 24; 10668bf5c682Smrg uint32_t rgb[3]; 10678bf5c682Smrg int i; 10688bf5c682Smrg 1069446f62d6Smrg if (premultiplied) { 1070446f62d6Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1, 18, 4, 0, 0) 1071446f62d6Smrg if (alpha == 0 && (*argb & 0xffffff) != 0) { 1072446f62d6Smrg /* Doesn't look like premultiplied alpha */ 1073446f62d6Smrg *premultiplied = FALSE; 1074446f62d6Smrg return FALSE; 1075446f62d6Smrg } 1076446f62d6Smrg#endif 10778bf5c682Smrg 1078446f62d6Smrg if (!(*apply_gamma)) 1079446f62d6Smrg return TRUE; 1080446f62d6Smrg 1081446f62d6Smrg if (*argb > (alpha | alpha << 8 | alpha << 16 | alpha << 24)) { 1082446f62d6Smrg /* Un-premultiplied R/G/B would overflow gamma LUT, 1083446f62d6Smrg * don't apply gamma correction 1084446f62d6Smrg */ 1085446f62d6Smrg *apply_gamma = FALSE; 1086446f62d6Smrg return FALSE; 1087446f62d6Smrg } 1088446f62d6Smrg } 1089446f62d6Smrg 1090446f62d6Smrg if (!alpha) { 1091446f62d6Smrg *argb = 0; 1092446f62d6Smrg return TRUE; 1093446f62d6Smrg } 10948bf5c682Smrg 1095446f62d6Smrg /* Extract RGB */ 10968bf5c682Smrg for (i = 0; i < 3; i++) 1097446f62d6Smrg rgb[i] = (*argb >> (i * 8)) & 0xff; 1098446f62d6Smrg 1099446f62d6Smrg if (premultiplied) { 1100446f62d6Smrg /* Un-premultiply alpha */ 1101446f62d6Smrg for (i = 0; i < 3; i++) 1102446f62d6Smrg rgb[i] = rgb[i] * 0xff / alpha; 1103446f62d6Smrg } 11048bf5c682Smrg 1105446f62d6Smrg if (*apply_gamma) { 1106446f62d6Smrg rgb[0] = crtc->gamma_blue[rgb[0]] >> 8; 1107446f62d6Smrg rgb[1] = crtc->gamma_green[rgb[1]] >> 8; 1108446f62d6Smrg rgb[2] = crtc->gamma_red[rgb[2]] >> 8; 1109446f62d6Smrg } 11108bf5c682Smrg 1111446f62d6Smrg /* Premultiply alpha */ 1112446f62d6Smrg for (i = 0; i < 3; i++) 1113446f62d6Smrg rgb[i] = rgb[i] * alpha / 0xff; 1114446f62d6Smrg 1115446f62d6Smrg *argb = alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0]; 1116446f62d6Smrg return TRUE; 11178bf5c682Smrg} 11188bf5c682Smrg 1119de2362d3Smrgstatic void 1120de2362d3Smrgdrmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image) 1121de2362d3Smrg{ 112218781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 112318781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1124de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1125446f62d6Smrg unsigned id = drmmode_crtc->cursor_id; 1126446f62d6Smrg Bool premultiplied = TRUE; 1127446f62d6Smrg Bool apply_gamma = TRUE; 1128446f62d6Smrg uint32_t argb; 1129de2362d3Smrg uint32_t *ptr; 1130de2362d3Smrg 1131446f62d6Smrg if (drmmode_crtc->cursor && 1132446f62d6Smrg XF86_CRTC_CONFIG_PTR(pScrn)->cursor != drmmode_crtc->cursor) 1133446f62d6Smrg id ^= 1; 1134446f62d6Smrg 1135de2362d3Smrg /* cursor should be mapped already */ 1136446f62d6Smrg ptr = (uint32_t *)(drmmode_crtc->cursor_bo[id]->ptr); 1137446f62d6Smrg 1138446f62d6Smrg if (crtc->scrn->depth != 24 && crtc->scrn->depth != 32) 1139446f62d6Smrg apply_gamma = FALSE; 1140de2362d3Smrg 11418bf5c682Smrg#if XF86_CRTC_VERSION < 7 114218781e08Smrg if (crtc->driverIsPerformingTransform) { 114318781e08Smrg uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h; 114418781e08Smrg int dstx, dsty; 114518781e08Smrg int srcoffset; 114618781e08Smrg 1147446f62d6Smrgretry_transform: 114818781e08Smrg for (dsty = 0; dsty < cursor_h; dsty++) { 114918781e08Smrg for (dstx = 0; dstx < cursor_w; dstx++) { 115018781e08Smrg srcoffset = drmmode_cursor_src_offset(crtc->rotation, 115118781e08Smrg cursor_w, 115218781e08Smrg cursor_h, 115318781e08Smrg dstx, dsty); 1154446f62d6Smrg argb = image[srcoffset]; 1155446f62d6Smrg if (!drmmode_cursor_pixel(crtc, &argb, &premultiplied, 1156446f62d6Smrg &apply_gamma)) 1157446f62d6Smrg goto retry_transform; 115818781e08Smrg 1159446f62d6Smrg ptr[dsty * info->cursor_w + dstx] = cpu_to_le32(argb); 116018781e08Smrg } 116118781e08Smrg } 116218781e08Smrg } else 116318781e08Smrg#endif 116418781e08Smrg { 116518781e08Smrg uint32_t cursor_size = info->cursor_w * info->cursor_h; 116618781e08Smrg int i; 116718781e08Smrg 1168446f62d6Smrgretry: 1169446f62d6Smrg for (i = 0; i < cursor_size; i++) { 1170446f62d6Smrg argb = image[i]; 1171446f62d6Smrg if (!drmmode_cursor_pixel(crtc, &argb, &premultiplied, 1172446f62d6Smrg &apply_gamma)) 1173446f62d6Smrg goto retry; 1174446f62d6Smrg 1175446f62d6Smrg ptr[i] = cpu_to_le32(argb); 1176446f62d6Smrg } 1177446f62d6Smrg } 1178446f62d6Smrg 1179446f62d6Smrg if (id != drmmode_crtc->cursor_id) { 1180446f62d6Smrg drmmode_crtc->cursor_id = id; 1181446f62d6Smrg crtc->funcs->show_cursor(crtc); 118218781e08Smrg } 1183de2362d3Smrg} 1184de2362d3Smrg 118518781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 118618781e08Smrg 118718781e08Smrgstatic Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image) 118818781e08Smrg{ 118918781e08Smrg if (!drmmode_can_use_hw_cursor(crtc)) 119018781e08Smrg return FALSE; 119118781e08Smrg 119218781e08Smrg drmmode_load_cursor_argb(crtc, image); 119318781e08Smrg return TRUE; 119418781e08Smrg} 119518781e08Smrg 119618781e08Smrg#endif 1197de2362d3Smrg 1198de2362d3Smrgstatic void 1199de2362d3Smrgdrmmode_hide_cursor (xf86CrtcPtr crtc) 1200de2362d3Smrg{ 120118781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 120218781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1203de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 12048bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 1205de2362d3Smrg 12068bf5c682Smrg drmModeSetCursor(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 120718781e08Smrg info->cursor_w, info->cursor_h); 1208446f62d6Smrg drmmode_crtc->cursor = NULL; 1209de2362d3Smrg} 1210de2362d3Smrg 1211de2362d3Smrgstatic void 1212de2362d3Smrgdrmmode_show_cursor (xf86CrtcPtr crtc) 1213de2362d3Smrg{ 121418781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 121518781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1216de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 12178bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 1218446f62d6Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1219446f62d6Smrg CursorPtr cursor = xf86_config->cursor; 1220446f62d6Smrg int xhot = cursor->bits->xhot; 1221446f62d6Smrg int yhot = cursor->bits->yhot; 122218781e08Smrg static Bool use_set_cursor2 = TRUE; 1223446f62d6Smrg struct drm_mode_cursor2 arg; 1224446f62d6Smrg 1225446f62d6Smrg drmmode_crtc->cursor = xf86_config->cursor; 1226446f62d6Smrg 1227446f62d6Smrg memset(&arg, 0, sizeof(arg)); 1228446f62d6Smrg 1229446f62d6Smrg arg.handle = drmmode_crtc->cursor_bo[drmmode_crtc->cursor_id]->handle; 1230446f62d6Smrg arg.flags = DRM_MODE_CURSOR_BO; 1231446f62d6Smrg arg.crtc_id = drmmode_crtc->mode_crtc->crtc_id; 1232446f62d6Smrg arg.width = info->cursor_w; 1233446f62d6Smrg arg.height = info->cursor_h; 1234446f62d6Smrg 1235446f62d6Smrg if (crtc->rotation != RR_Rotate_0 && 1236446f62d6Smrg crtc->rotation != (RR_Rotate_180 | RR_Reflect_X | 1237446f62d6Smrg RR_Reflect_Y)) { 1238446f62d6Smrg int t; 1239446f62d6Smrg 1240446f62d6Smrg /* Reflect & rotate hotspot position */ 1241446f62d6Smrg if (crtc->rotation & RR_Reflect_X) 1242446f62d6Smrg xhot = info->cursor_w - xhot - 1; 1243446f62d6Smrg if (crtc->rotation & RR_Reflect_Y) 1244446f62d6Smrg yhot = info->cursor_h - yhot - 1; 1245446f62d6Smrg 1246446f62d6Smrg switch (crtc->rotation & 0xf) { 1247446f62d6Smrg case RR_Rotate_90: 1248446f62d6Smrg t = xhot; 1249446f62d6Smrg xhot = yhot; 1250446f62d6Smrg yhot = info->cursor_w - t - 1; 1251446f62d6Smrg break; 1252446f62d6Smrg case RR_Rotate_180: 1253446f62d6Smrg xhot = info->cursor_w - xhot - 1; 1254446f62d6Smrg yhot = info->cursor_h - yhot - 1; 1255446f62d6Smrg break; 1256446f62d6Smrg case RR_Rotate_270: 1257446f62d6Smrg t = xhot; 1258446f62d6Smrg xhot = info->cursor_h - yhot - 1; 1259446f62d6Smrg yhot = t; 1260446f62d6Smrg } 1261446f62d6Smrg } 1262446f62d6Smrg 1263446f62d6Smrg if (xhot != drmmode_crtc->cursor_xhot || yhot != drmmode_crtc->cursor_yhot) { 1264446f62d6Smrg arg.flags |= DRM_MODE_CURSOR_MOVE; 1265446f62d6Smrg arg.x = drmmode_crtc->cursor_x += drmmode_crtc->cursor_xhot - xhot; 1266446f62d6Smrg arg.y = drmmode_crtc->cursor_y += drmmode_crtc->cursor_yhot - yhot; 1267446f62d6Smrg drmmode_crtc->cursor_xhot = xhot; 1268446f62d6Smrg drmmode_crtc->cursor_yhot = yhot; 1269446f62d6Smrg } 127018781e08Smrg 127118781e08Smrg if (use_set_cursor2) { 127218781e08Smrg int ret; 127318781e08Smrg 1274446f62d6Smrg arg.hot_x = xhot; 1275446f62d6Smrg arg.hot_y = yhot; 12767314432eSmrg 1277446f62d6Smrg ret = drmIoctl(pRADEONEnt->fd, DRM_IOCTL_MODE_CURSOR2, &arg); 127818781e08Smrg if (ret == -EINVAL) 127918781e08Smrg use_set_cursor2 = FALSE; 128018781e08Smrg else 128118781e08Smrg return; 128218781e08Smrg } 128318781e08Smrg 1284446f62d6Smrg drmIoctl(pRADEONEnt->fd, DRM_IOCTL_MODE_CURSOR, &arg); 1285de2362d3Smrg} 1286de2362d3Smrg 12873ed65abbSmrg/* Xorg expects a non-NULL return value from drmmode_crtc_shadow_allocate, and 12883ed65abbSmrg * passes that back to drmmode_crtc_scanout_create; it doesn't use it for 12893ed65abbSmrg * anything else. 12903ed65abbSmrg */ 1291de2362d3Smrgstatic void * 1292de2362d3Smrgdrmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 1293de2362d3Smrg{ 1294de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 12957821949aSmrg 12963ed65abbSmrg if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 12973ed65abbSmrg height)) 12983ed65abbSmrg return NULL; 12993ed65abbSmrg 13003ed65abbSmrg return (void*)~0UL; 1301de2362d3Smrg} 1302de2362d3Smrg 1303de2362d3Smrgstatic PixmapPtr 1304de2362d3Smrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 1305de2362d3Smrg{ 1306de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1307de2362d3Smrg 13083ed65abbSmrg if (!data) { 13093ed65abbSmrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 13103ed65abbSmrg height); 13113ed65abbSmrg } 13123ed65abbSmrg 13133ed65abbSmrg return drmmode_crtc->rotate.pixmap; 1314de2362d3Smrg} 1315de2362d3Smrg 1316de2362d3Smrgstatic void 13177821949aSmrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) 1318de2362d3Smrg{ 1319de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1320de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 1321de2362d3Smrg 132218781e08Smrg drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate); 13237821949aSmrg} 1324de2362d3Smrg 13257821949aSmrgstatic void 13267821949aSmrgdrmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 13277821949aSmrg uint16_t *blue, int size) 13287821949aSmrg{ 13298bf5c682Smrg ScrnInfoPtr scrn = crtc->scrn; 13308bf5c682Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 13318bf5c682Smrg RADEONInfoPtr info = RADEONPTR(scrn); 13328bf5c682Smrg int i; 13338bf5c682Smrg 13348bf5c682Smrg drmmode_crtc_gamma_do_set(crtc, red, green, blue, size); 13358bf5c682Smrg 13368bf5c682Smrg /* Compute index of this CRTC into xf86_config->crtc */ 13378bf5c682Smrg for (i = 0; xf86_config->crtc[i] != crtc; i++) {} 13388bf5c682Smrg 13398bf5c682Smrg if (info->hwcursor_disabled & (1 << i)) 13408bf5c682Smrg return; 13417314432eSmrg 13428bf5c682Smrg#ifdef HAVE_XF86_CURSOR_RESET_CURSOR 13438bf5c682Smrg xf86CursorResetCursor(scrn->pScreen); 13448bf5c682Smrg#else 13458bf5c682Smrg xf86_reload_cursors(scrn->pScreen); 13468bf5c682Smrg#endif 134718781e08Smrg} 134818781e08Smrg 134918781e08Smrgstatic Bool 135018781e08Smrgdrmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) 135118781e08Smrg{ 135218781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 13533ed65abbSmrg unsigned scanout_id = drmmode_crtc->scanout_id; 135418781e08Smrg ScreenPtr screen = crtc->scrn->pScreen; 135518781e08Smrg PixmapDirtyUpdatePtr dirty; 135618781e08Smrg 135718781e08Smrg xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 13588bf5c682Smrg if (radeon_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) { 13598bf5c682Smrg PixmapStopDirtyTracking(dirty->src, dirty->slave_dst); 13608bf5c682Smrg break; 13618bf5c682Smrg } 136218781e08Smrg } 136318781e08Smrg 1364446f62d6Smrg drmmode_crtc_scanout_free(crtc); 13658bf5c682Smrg drmmode_crtc->prime_scanout_pixmap = NULL; 13668bf5c682Smrg 136718781e08Smrg if (!ppix) 136818781e08Smrg return TRUE; 136918781e08Smrg 137018781e08Smrg if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0], 137118781e08Smrg ppix->drawable.width, 137218781e08Smrg ppix->drawable.height)) 137318781e08Smrg return FALSE; 137418781e08Smrg 13753ed65abbSmrg if (drmmode_crtc->tear_free && 137618781e08Smrg !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 137718781e08Smrg ppix->drawable.width, 137818781e08Smrg ppix->drawable.height)) { 1379446f62d6Smrg drmmode_crtc_scanout_free(crtc); 138018781e08Smrg return FALSE; 138118781e08Smrg } 138218781e08Smrg 13838bf5c682Smrg drmmode_crtc->prime_scanout_pixmap = ppix; 13848bf5c682Smrg 13858bf5c682Smrg#ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC 13868bf5c682Smrg PixmapStartDirtyTracking(&ppix->drawable, 13878bf5c682Smrg drmmode_crtc->scanout[scanout_id].pixmap, 13888bf5c682Smrg 0, 0, 0, 0, RR_Rotate_0); 13898bf5c682Smrg#elif defined(HAS_DIRTYTRACKING_ROTATION) 13903ed65abbSmrg PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 139118781e08Smrg 0, 0, 0, 0, RR_Rotate_0); 139218781e08Smrg#elif defined(HAS_DIRTYTRACKING2) 13933ed65abbSmrg PixmapStartDirtyTracking2(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 139418781e08Smrg 0, 0, 0, 0); 139518781e08Smrg#else 13963ed65abbSmrg PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 0, 0); 139718781e08Smrg#endif 139818781e08Smrg return TRUE; 1399de2362d3Smrg} 1400de2362d3Smrg 140118781e08Smrgstatic xf86CrtcFuncsRec drmmode_crtc_funcs = { 1402de2362d3Smrg .dpms = drmmode_crtc_dpms, 1403de2362d3Smrg .set_mode_major = drmmode_set_mode_major, 1404de2362d3Smrg .set_cursor_colors = drmmode_set_cursor_colors, 1405de2362d3Smrg .set_cursor_position = drmmode_set_cursor_position, 1406de2362d3Smrg .show_cursor = drmmode_show_cursor, 1407de2362d3Smrg .hide_cursor = drmmode_hide_cursor, 1408de2362d3Smrg .load_cursor_argb = drmmode_load_cursor_argb, 140918781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 141018781e08Smrg .load_cursor_argb_check = drmmode_load_cursor_argb_check, 141118781e08Smrg#endif 1412de2362d3Smrg 1413de2362d3Smrg .gamma_set = drmmode_crtc_gamma_set, 1414de2362d3Smrg .shadow_create = drmmode_crtc_shadow_create, 1415de2362d3Smrg .shadow_allocate = drmmode_crtc_shadow_allocate, 1416de2362d3Smrg .shadow_destroy = drmmode_crtc_shadow_destroy, 1417de2362d3Smrg .destroy = NULL, /* XXX */ 141818781e08Smrg .set_scanout_pixmap = drmmode_set_scanout_pixmap, 1419de2362d3Smrg}; 1420de2362d3Smrg 1421de2362d3Smrgint drmmode_get_crtc_id(xf86CrtcPtr crtc) 1422de2362d3Smrg{ 1423de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1424de2362d3Smrg return drmmode_crtc->hw_id; 1425de2362d3Smrg} 1426de2362d3Smrg 1427de2362d3Smrgvoid drmmode_crtc_hw_id(xf86CrtcPtr crtc) 1428de2362d3Smrg{ 1429de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 14308bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 1431de2362d3Smrg struct drm_radeon_info ginfo; 1432de2362d3Smrg int r; 1433de2362d3Smrg uint32_t tmp; 1434de2362d3Smrg 1435de2362d3Smrg memset(&ginfo, 0, sizeof(ginfo)); 1436de2362d3Smrg ginfo.request = 0x4; 1437de2362d3Smrg tmp = drmmode_crtc->mode_crtc->crtc_id; 1438de2362d3Smrg ginfo.value = (uintptr_t)&tmp; 14398bf5c682Smrg r = drmCommandWriteRead(pRADEONEnt->fd, DRM_RADEON_INFO, &ginfo, sizeof(ginfo)); 1440de2362d3Smrg if (r) { 1441de2362d3Smrg drmmode_crtc->hw_id = -1; 1442de2362d3Smrg return; 1443de2362d3Smrg } 1444de2362d3Smrg drmmode_crtc->hw_id = tmp; 1445de2362d3Smrg} 1446de2362d3Smrg 144718781e08Smrgstatic unsigned int 144818781e08Smrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num) 1449de2362d3Smrg{ 1450de2362d3Smrg xf86CrtcPtr crtc; 1451de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc; 145218781e08Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 14538bf5c682Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1454de2362d3Smrg 14558bf5c682Smrg crtc = xf86CrtcCreate(pScrn, &info->drmmode_crtc_funcs); 145639413783Smrg if (!crtc) 145718781e08Smrg return 0; 1458de2362d3Smrg 1459de2362d3Smrg drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); 14608bf5c682Smrg drmmode_crtc->mode_crtc = drmModeGetCrtc(pRADEONEnt->fd, mode_res->crtcs[num]); 1461de2362d3Smrg drmmode_crtc->drmmode = drmmode; 146218781e08Smrg drmmode_crtc->dpms_mode = DPMSModeOff; 1463de2362d3Smrg crtc->driver_private = drmmode_crtc; 1464de2362d3Smrg drmmode_crtc_hw_id(crtc); 1465de2362d3Smrg 146618781e08Smrg /* Mark num'th crtc as in use on this device. */ 146718781e08Smrg pRADEONEnt->assigned_crtcs |= (1 << num); 146818781e08Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 146918781e08Smrg "Allocated crtc nr. %d to this screen.\n", num); 147018781e08Smrg 147118781e08Smrg return 1; 1472de2362d3Smrg} 1473de2362d3Smrg 14748bf5c682Smrg/* 14758bf5c682Smrg * Update all of the property values for an output 14768bf5c682Smrg */ 14778bf5c682Smrgstatic void 14788bf5c682Smrgdrmmode_output_update_properties(xf86OutputPtr output) 14798bf5c682Smrg{ 14808bf5c682Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 14818bf5c682Smrg int i, j, k; 14828bf5c682Smrg int err; 14838bf5c682Smrg drmModeConnectorPtr koutput; 14848bf5c682Smrg 14858bf5c682Smrg /* Use the most recently fetched values from the kernel */ 14868bf5c682Smrg koutput = drmmode_output->mode_output; 14878bf5c682Smrg 14888bf5c682Smrg if (!koutput) 14898bf5c682Smrg return; 14908bf5c682Smrg 14918bf5c682Smrg for (i = 0; i < drmmode_output->num_props; i++) { 14928bf5c682Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 14938bf5c682Smrg 14948bf5c682Smrg for (j = 0; j < koutput->count_props; j++) { 14958bf5c682Smrg if (koutput->props[j] != p->mode_prop->prop_id) 14968bf5c682Smrg continue; 14978bf5c682Smrg 14988bf5c682Smrg /* Check to see if the property value has changed */ 14998bf5c682Smrg if (koutput->prop_values[j] == p->value) 15008bf5c682Smrg break; 15018bf5c682Smrg 15028bf5c682Smrg p->value = koutput->prop_values[j]; 15038bf5c682Smrg 15048bf5c682Smrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 15058bf5c682Smrg INT32 value = p->value; 15068bf5c682Smrg 15078bf5c682Smrg err = RRChangeOutputProperty(output->randr_output, 15088bf5c682Smrg p->atoms[0], XA_INTEGER, 15098bf5c682Smrg 32, PropModeReplace, 1, 15108bf5c682Smrg &value, FALSE, TRUE); 15118bf5c682Smrg if (err != 0) { 15128bf5c682Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 15138bf5c682Smrg "RRChangeOutputProperty error, %d\n", 15148bf5c682Smrg err); 15158bf5c682Smrg } 15168bf5c682Smrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 15178bf5c682Smrg for (k = 0; k < p->mode_prop->count_enums; k++) { 15188bf5c682Smrg if (p->mode_prop->enums[k].value == p->value) 15198bf5c682Smrg break; 15208bf5c682Smrg } 15218bf5c682Smrg if (k < p->mode_prop->count_enums) { 15228bf5c682Smrg err = RRChangeOutputProperty(output->randr_output, 15238bf5c682Smrg p->atoms[0], XA_ATOM, 15248bf5c682Smrg 32, PropModeReplace, 1, 15258bf5c682Smrg &p->atoms[k + 1], FALSE, 15268bf5c682Smrg TRUE); 15278bf5c682Smrg if (err != 0) { 15288bf5c682Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 15298bf5c682Smrg "RRChangeOutputProperty error, %d\n", 15308bf5c682Smrg err); 15318bf5c682Smrg } 15328bf5c682Smrg } 15338bf5c682Smrg } 15348bf5c682Smrg 15358bf5c682Smrg break; 15368bf5c682Smrg } 15378bf5c682Smrg } 15388bf5c682Smrg} 15398bf5c682Smrg 1540de2362d3Smrgstatic xf86OutputStatus 1541de2362d3Smrgdrmmode_output_detect(xf86OutputPtr output) 1542de2362d3Smrg{ 1543de2362d3Smrg /* go to the hw and retrieve a new output struct */ 1544de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 15458bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 1546de2362d3Smrg xf86OutputStatus status; 1547de2362d3Smrg drmModeFreeConnector(drmmode_output->mode_output); 1548de2362d3Smrg 15498bf5c682Smrg drmmode_output->mode_output = 15508bf5c682Smrg drmModeGetConnector(pRADEONEnt->fd, drmmode_output->output_id); 15518bf5c682Smrg if (!drmmode_output->mode_output) { 15528bf5c682Smrg drmmode_output->output_id = -1; 155318781e08Smrg return XF86OutputStatusDisconnected; 15548bf5c682Smrg } 15558bf5c682Smrg 15568bf5c682Smrg drmmode_output_update_properties(output); 1557de2362d3Smrg 1558de2362d3Smrg switch (drmmode_output->mode_output->connection) { 1559de2362d3Smrg case DRM_MODE_CONNECTED: 1560de2362d3Smrg status = XF86OutputStatusConnected; 1561de2362d3Smrg break; 1562de2362d3Smrg case DRM_MODE_DISCONNECTED: 1563de2362d3Smrg status = XF86OutputStatusDisconnected; 1564de2362d3Smrg break; 1565de2362d3Smrg default: 1566de2362d3Smrg case DRM_MODE_UNKNOWNCONNECTION: 1567de2362d3Smrg status = XF86OutputStatusUnknown; 1568de2362d3Smrg break; 1569de2362d3Smrg } 1570de2362d3Smrg return status; 1571de2362d3Smrg} 1572de2362d3Smrg 1573de2362d3Smrgstatic Bool 1574de2362d3Smrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) 1575de2362d3Smrg{ 1576de2362d3Smrg return MODE_OK; 1577de2362d3Smrg} 1578de2362d3Smrg 1579446f62d6Smrgstatic void 1580446f62d6Smrgdrmmode_output_attach_tile(xf86OutputPtr output) 1581446f62d6Smrg{ 1582446f62d6Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1, 17, 99, 901, 0) 1583446f62d6Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1584446f62d6Smrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 1585446f62d6Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 1586446f62d6Smrg struct xf86CrtcTileInfo tile_info, *set = NULL; 1587446f62d6Smrg int i; 1588446f62d6Smrg 1589446f62d6Smrg if (!koutput) { 1590446f62d6Smrg xf86OutputSetTile(output, NULL); 1591446f62d6Smrg return; 1592446f62d6Smrg } 1593446f62d6Smrg 1594446f62d6Smrg /* look for a TILE property */ 1595446f62d6Smrg for (i = 0; i < koutput->count_props; i++) { 1596446f62d6Smrg drmModePropertyPtr props; 1597446f62d6Smrg props = drmModeGetProperty(pRADEONEnt->fd, koutput->props[i]); 1598446f62d6Smrg if (!props) 1599446f62d6Smrg continue; 1600446f62d6Smrg 1601446f62d6Smrg if (!(props->flags & DRM_MODE_PROP_BLOB)) { 1602446f62d6Smrg drmModeFreeProperty(props); 1603446f62d6Smrg continue; 1604446f62d6Smrg } 1605446f62d6Smrg 1606446f62d6Smrg if (!strcmp(props->name, "TILE")) { 1607446f62d6Smrg drmModeFreePropertyBlob(drmmode_output->tile_blob); 1608446f62d6Smrg drmmode_output->tile_blob = 1609446f62d6Smrg drmModeGetPropertyBlob(pRADEONEnt->fd, 1610446f62d6Smrg koutput->prop_values[i]); 1611446f62d6Smrg } 1612446f62d6Smrg drmModeFreeProperty(props); 1613446f62d6Smrg } 1614446f62d6Smrg if (drmmode_output->tile_blob) { 1615446f62d6Smrg if (xf86OutputParseKMSTile(drmmode_output->tile_blob->data, 1616446f62d6Smrg drmmode_output->tile_blob->length, 1617446f62d6Smrg &tile_info) == TRUE) 1618446f62d6Smrg set = &tile_info; 1619446f62d6Smrg } 1620446f62d6Smrg xf86OutputSetTile(output, set); 1621446f62d6Smrg#endif 1622446f62d6Smrg} 1623446f62d6Smrg 16248bf5c682Smrgstatic int 16258bf5c682Smrgkoutput_get_prop_idx(int fd, drmModeConnectorPtr koutput, 16268bf5c682Smrg int type, const char *name) 16278bf5c682Smrg{ 16288bf5c682Smrg int idx = -1; 16298bf5c682Smrg 16308bf5c682Smrg for (int i = 0; i < koutput->count_props; i++) { 16318bf5c682Smrg drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]); 16328bf5c682Smrg 16338bf5c682Smrg if (!prop) 16348bf5c682Smrg continue; 16358bf5c682Smrg 16368bf5c682Smrg if (drm_property_type_is(prop, type) && !strcmp(prop->name, name)) 16378bf5c682Smrg idx = i; 16388bf5c682Smrg 16398bf5c682Smrg drmModeFreeProperty(prop); 16408bf5c682Smrg 16418bf5c682Smrg if (idx > -1) 16428bf5c682Smrg break; 16438bf5c682Smrg } 16448bf5c682Smrg 16458bf5c682Smrg return idx; 16468bf5c682Smrg} 16478bf5c682Smrg 16488bf5c682Smrgstatic int 16498bf5c682Smrgkoutput_get_prop_id(int fd, drmModeConnectorPtr koutput, 16508bf5c682Smrg int type, const char *name) 16518bf5c682Smrg{ 16528bf5c682Smrg int idx = koutput_get_prop_idx(fd, koutput, type, name); 16538bf5c682Smrg 16548bf5c682Smrg return (idx > -1) ? koutput->props[idx] : -1; 16558bf5c682Smrg} 16568bf5c682Smrg 16578bf5c682Smrgstatic drmModePropertyBlobPtr 16588bf5c682Smrgkoutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name) 16598bf5c682Smrg{ 16608bf5c682Smrg drmModePropertyBlobPtr blob = NULL; 16618bf5c682Smrg int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name); 16628bf5c682Smrg 16638bf5c682Smrg if (idx > -1) 16648bf5c682Smrg blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]); 16658bf5c682Smrg 16668bf5c682Smrg return blob; 16678bf5c682Smrg} 16688bf5c682Smrg 1669de2362d3Smrgstatic DisplayModePtr 1670de2362d3Smrgdrmmode_output_get_modes(xf86OutputPtr output) 1671de2362d3Smrg{ 1672de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1673de2362d3Smrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 16748bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 1675de2362d3Smrg int i; 1676de2362d3Smrg DisplayModePtr Modes = NULL, Mode; 1677de2362d3Smrg xf86MonPtr mon = NULL; 1678de2362d3Smrg 167918781e08Smrg if (!koutput) 168018781e08Smrg return NULL; 168118781e08Smrg 16828bf5c682Smrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 16838bf5c682Smrg 1684de2362d3Smrg /* look for an EDID property */ 16858bf5c682Smrg drmmode_output->edid_blob = 16868bf5c682Smrg koutput_get_prop_blob(pRADEONEnt->fd, koutput, "EDID"); 1687de2362d3Smrg 1688de2362d3Smrg if (drmmode_output->edid_blob) { 1689de2362d3Smrg mon = xf86InterpretEDID(output->scrn->scrnIndex, 1690de2362d3Smrg drmmode_output->edid_blob->data); 1691de2362d3Smrg if (mon && drmmode_output->edid_blob->length > 128) 1692de2362d3Smrg mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 1693de2362d3Smrg } 1694de2362d3Smrg xf86OutputSetEDID(output, mon); 1695de2362d3Smrg 1696446f62d6Smrg drmmode_output_attach_tile(output); 1697446f62d6Smrg 1698de2362d3Smrg /* modes should already be available */ 1699de2362d3Smrg for (i = 0; i < koutput->count_modes; i++) { 1700de2362d3Smrg Mode = xnfalloc(sizeof(DisplayModeRec)); 1701de2362d3Smrg 1702de2362d3Smrg drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode); 1703de2362d3Smrg Modes = xf86ModesAdd(Modes, Mode); 1704de2362d3Smrg 1705de2362d3Smrg } 1706de2362d3Smrg return Modes; 1707de2362d3Smrg} 1708de2362d3Smrg 1709de2362d3Smrgstatic void 1710de2362d3Smrgdrmmode_output_destroy(xf86OutputPtr output) 1711de2362d3Smrg{ 1712de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1713de2362d3Smrg int i; 1714de2362d3Smrg 1715446f62d6Smrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 1716446f62d6Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1, 17, 99, 901, 0) 1717446f62d6Smrg drmModeFreePropertyBlob(drmmode_output->tile_blob); 1718446f62d6Smrg#endif 1719446f62d6Smrg 1720de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 1721de2362d3Smrg drmModeFreeProperty(drmmode_output->props[i].mode_prop); 1722de2362d3Smrg free(drmmode_output->props[i].atoms); 1723de2362d3Smrg } 1724de2362d3Smrg for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) { 1725de2362d3Smrg drmModeFreeEncoder(drmmode_output->mode_encoders[i]); 1726de2362d3Smrg } 172718781e08Smrg free(drmmode_output->mode_encoders); 1728de2362d3Smrg free(drmmode_output->props); 1729de2362d3Smrg drmModeFreeConnector(drmmode_output->mode_output); 1730de2362d3Smrg free(drmmode_output); 1731de2362d3Smrg output->driver_private = NULL; 1732de2362d3Smrg} 1733de2362d3Smrg 1734de2362d3Smrgstatic void 1735de2362d3Smrgdrmmode_output_dpms(xf86OutputPtr output, int mode) 1736de2362d3Smrg{ 1737de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 173818781e08Smrg xf86CrtcPtr crtc = output->crtc; 1739de2362d3Smrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 17408bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 1741de2362d3Smrg 174218781e08Smrg if (!koutput) 174318781e08Smrg return; 174418781e08Smrg 17458bf5c682Smrg if (mode != DPMSModeOn && crtc) 174618781e08Smrg drmmode_do_crtc_dpms(crtc, mode); 174718781e08Smrg 17488bf5c682Smrg drmModeConnectorSetProperty(pRADEONEnt->fd, koutput->connector_id, 1749de2362d3Smrg drmmode_output->dpms_enum_id, mode); 175018781e08Smrg 175118781e08Smrg if (mode == DPMSModeOn && crtc) { 175218781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 175318781e08Smrg 175418781e08Smrg if (drmmode_crtc->need_modeset) 175518781e08Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x, 175618781e08Smrg crtc->y); 175718781e08Smrg else 175818781e08Smrg drmmode_do_crtc_dpms(crtc, mode); 175918781e08Smrg } 1760de2362d3Smrg} 1761de2362d3Smrg 1762de2362d3Smrg 1763de2362d3Smrgstatic Bool 1764de2362d3Smrgdrmmode_property_ignore(drmModePropertyPtr prop) 1765de2362d3Smrg{ 1766de2362d3Smrg if (!prop) 1767de2362d3Smrg return TRUE; 1768de2362d3Smrg /* ignore blob prop */ 1769de2362d3Smrg if (prop->flags & DRM_MODE_PROP_BLOB) 1770de2362d3Smrg return TRUE; 1771de2362d3Smrg /* ignore standard property */ 1772de2362d3Smrg if (!strcmp(prop->name, "EDID") || 1773de2362d3Smrg !strcmp(prop->name, "DPMS")) 1774de2362d3Smrg return TRUE; 1775de2362d3Smrg 1776de2362d3Smrg return FALSE; 1777de2362d3Smrg} 1778de2362d3Smrg 1779de2362d3Smrgstatic void 1780de2362d3Smrgdrmmode_output_create_resources(xf86OutputPtr output) 1781de2362d3Smrg{ 17823ed65abbSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1783de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1784de2362d3Smrg drmModeConnectorPtr mode_output = drmmode_output->mode_output; 17858bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 17863ed65abbSmrg drmModePropertyPtr drmmode_prop, tearfree_prop; 1787de2362d3Smrg int i, j, err; 178839413783Smrg Atom name; 178939413783Smrg 179039413783Smrg /* Create CONNECTOR_ID property */ 179139413783Smrg name = MakeAtom("CONNECTOR_ID", 12, TRUE); 179239413783Smrg if (name != BAD_RESOURCE) { 179339413783Smrg INT32 value = mode_output->connector_id; 179439413783Smrg 179539413783Smrg err = RRConfigureOutputProperty(output->randr_output, name, 179639413783Smrg FALSE, FALSE, TRUE, 1, &value); 179739413783Smrg if (err != Success) { 179839413783Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 179939413783Smrg "RRConfigureOutputProperty error, %d\n", err); 180039413783Smrg } 180139413783Smrg 180239413783Smrg err = RRChangeOutputProperty(output->randr_output, name, 180339413783Smrg XA_INTEGER, 32, PropModeReplace, 1, 180439413783Smrg &value, FALSE, FALSE); 180539413783Smrg if (err != Success) { 180639413783Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 180739413783Smrg "RRChangeOutputProperty error, %d\n", err); 180839413783Smrg } 180939413783Smrg } 1810de2362d3Smrg 18113ed65abbSmrg drmmode_output->props = calloc(mode_output->count_props + 1, sizeof(drmmode_prop_rec)); 1812de2362d3Smrg if (!drmmode_output->props) 1813de2362d3Smrg return; 1814de2362d3Smrg 1815de2362d3Smrg drmmode_output->num_props = 0; 1816de2362d3Smrg for (i = 0, j = 0; i < mode_output->count_props; i++) { 18178bf5c682Smrg drmmode_prop = drmModeGetProperty(pRADEONEnt->fd, mode_output->props[i]); 1818de2362d3Smrg if (drmmode_property_ignore(drmmode_prop)) { 1819de2362d3Smrg drmModeFreeProperty(drmmode_prop); 1820de2362d3Smrg continue; 1821de2362d3Smrg } 1822de2362d3Smrg drmmode_output->props[j].mode_prop = drmmode_prop; 1823de2362d3Smrg drmmode_output->props[j].value = mode_output->prop_values[i]; 1824de2362d3Smrg drmmode_output->num_props++; 1825de2362d3Smrg j++; 1826de2362d3Smrg } 1827de2362d3Smrg 18283ed65abbSmrg /* Userspace-only property for TearFree */ 18293ed65abbSmrg tearfree_prop = calloc(1, sizeof(*tearfree_prop)); 18303ed65abbSmrg tearfree_prop->flags = DRM_MODE_PROP_ENUM; 183139413783Smrg strcpy(tearfree_prop->name, "TearFree"); 18323ed65abbSmrg tearfree_prop->count_enums = 3; 18333ed65abbSmrg tearfree_prop->enums = calloc(tearfree_prop->count_enums, 18343ed65abbSmrg sizeof(*tearfree_prop->enums)); 183539413783Smrg strcpy(tearfree_prop->enums[0].name, "off"); 183639413783Smrg strcpy(tearfree_prop->enums[1].name, "on"); 18373ed65abbSmrg tearfree_prop->enums[1].value = 1; 183839413783Smrg strcpy(tearfree_prop->enums[2].name, "auto"); 18393ed65abbSmrg tearfree_prop->enums[2].value = 2; 18403ed65abbSmrg drmmode_output->props[j].mode_prop = tearfree_prop; 18413ed65abbSmrg drmmode_output->props[j].value = info->tear_free; 18423ed65abbSmrg drmmode_output->tear_free = info->tear_free; 18433ed65abbSmrg drmmode_output->num_props++; 18443ed65abbSmrg 1845de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 1846de2362d3Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 1847de2362d3Smrg drmmode_prop = p->mode_prop; 1848de2362d3Smrg 1849de2362d3Smrg if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 1850de2362d3Smrg INT32 range[2]; 1851de2362d3Smrg INT32 value = p->value; 1852de2362d3Smrg 1853de2362d3Smrg p->num_atoms = 1; 1854de2362d3Smrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 1855de2362d3Smrg if (!p->atoms) 1856de2362d3Smrg continue; 1857de2362d3Smrg p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 1858de2362d3Smrg range[0] = drmmode_prop->values[0]; 1859de2362d3Smrg range[1] = drmmode_prop->values[1]; 1860de2362d3Smrg err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 1861de2362d3Smrg FALSE, TRUE, 1862de2362d3Smrg drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 1863de2362d3Smrg 2, range); 1864de2362d3Smrg if (err != 0) { 1865de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1866de2362d3Smrg "RRConfigureOutputProperty error, %d\n", err); 1867de2362d3Smrg } 1868de2362d3Smrg err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 1869de2362d3Smrg XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, TRUE); 1870de2362d3Smrg if (err != 0) { 1871de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1872de2362d3Smrg "RRChangeOutputProperty error, %d\n", err); 1873de2362d3Smrg } 1874de2362d3Smrg } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 1875de2362d3Smrg p->num_atoms = drmmode_prop->count_enums + 1; 1876de2362d3Smrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 1877de2362d3Smrg if (!p->atoms) 1878de2362d3Smrg continue; 1879de2362d3Smrg p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 1880de2362d3Smrg for (j = 1; j <= drmmode_prop->count_enums; j++) { 1881de2362d3Smrg struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; 1882de2362d3Smrg p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); 1883de2362d3Smrg } 1884de2362d3Smrg err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 1885de2362d3Smrg FALSE, FALSE, 1886de2362d3Smrg drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 1887de2362d3Smrg p->num_atoms - 1, (INT32 *)&p->atoms[1]); 1888de2362d3Smrg if (err != 0) { 1889de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1890de2362d3Smrg "RRConfigureOutputProperty error, %d\n", err); 1891de2362d3Smrg } 1892de2362d3Smrg for (j = 0; j < drmmode_prop->count_enums; j++) 1893de2362d3Smrg if (drmmode_prop->enums[j].value == p->value) 1894de2362d3Smrg break; 1895de2362d3Smrg /* there's always a matching value */ 1896de2362d3Smrg err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 1897de2362d3Smrg XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE); 1898de2362d3Smrg if (err != 0) { 1899de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1900de2362d3Smrg "RRChangeOutputProperty error, %d\n", err); 1901de2362d3Smrg } 1902de2362d3Smrg } 1903de2362d3Smrg } 1904de2362d3Smrg} 1905de2362d3Smrg 190639413783Smrgstatic void 190739413783Smrgdrmmode_output_set_tear_free(RADEONEntPtr pRADEONEnt, 190839413783Smrg drmmode_output_private_ptr drmmode_output, 190939413783Smrg xf86CrtcPtr crtc, int tear_free) 191039413783Smrg{ 191139413783Smrg if (drmmode_output->tear_free == tear_free) 191239413783Smrg return; 191339413783Smrg 191439413783Smrg drmmode_output->tear_free = tear_free; 191539413783Smrg 191639413783Smrg if (crtc) { 191739413783Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 191839413783Smrg crtc->x, crtc->y); 191939413783Smrg } 192039413783Smrg} 192139413783Smrg 1922de2362d3Smrgstatic Bool 1923de2362d3Smrgdrmmode_output_set_property(xf86OutputPtr output, Atom property, 1924de2362d3Smrg RRPropertyValuePtr value) 1925de2362d3Smrg{ 1926de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 19278bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 1928de2362d3Smrg int i; 1929de2362d3Smrg 1930de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 1931de2362d3Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 1932de2362d3Smrg 1933de2362d3Smrg if (p->atoms[0] != property) 1934de2362d3Smrg continue; 1935de2362d3Smrg 1936de2362d3Smrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 1937de2362d3Smrg uint32_t val; 1938de2362d3Smrg 1939de2362d3Smrg if (value->type != XA_INTEGER || value->format != 32 || 1940de2362d3Smrg value->size != 1) 1941de2362d3Smrg return FALSE; 1942de2362d3Smrg val = *(uint32_t *)value->data; 1943de2362d3Smrg 19448bf5c682Smrg drmModeConnectorSetProperty(pRADEONEnt->fd, drmmode_output->output_id, 1945de2362d3Smrg p->mode_prop->prop_id, (uint64_t)val); 1946de2362d3Smrg return TRUE; 1947de2362d3Smrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 1948de2362d3Smrg Atom atom; 1949de2362d3Smrg const char *name; 1950de2362d3Smrg int j; 1951de2362d3Smrg 1952de2362d3Smrg if (value->type != XA_ATOM || value->format != 32 || value->size != 1) 1953de2362d3Smrg return FALSE; 1954de2362d3Smrg memcpy(&atom, value->data, 4); 19558bf5c682Smrg if (!(name = NameForAtom(atom))) 19568bf5c682Smrg return FALSE; 1957de2362d3Smrg 1958de2362d3Smrg /* search for matching name string, then set its value down */ 1959de2362d3Smrg for (j = 0; j < p->mode_prop->count_enums; j++) { 1960de2362d3Smrg if (!strcmp(p->mode_prop->enums[j].name, name)) { 19613ed65abbSmrg if (i == (drmmode_output->num_props - 1)) { 196239413783Smrg drmmode_output_set_tear_free(pRADEONEnt, drmmode_output, 196339413783Smrg output->crtc, j); 19643ed65abbSmrg } else { 19658bf5c682Smrg drmModeConnectorSetProperty(pRADEONEnt->fd, 19663ed65abbSmrg drmmode_output->output_id, 19673ed65abbSmrg p->mode_prop->prop_id, 19683ed65abbSmrg p->mode_prop->enums[j].value); 19693ed65abbSmrg } 19703ed65abbSmrg 1971de2362d3Smrg return TRUE; 1972de2362d3Smrg } 1973de2362d3Smrg } 1974de2362d3Smrg } 1975de2362d3Smrg } 1976de2362d3Smrg 1977de2362d3Smrg return TRUE; 1978de2362d3Smrg} 1979de2362d3Smrg 1980de2362d3Smrgstatic Bool 1981de2362d3Smrgdrmmode_output_get_property(xf86OutputPtr output, Atom property) 1982de2362d3Smrg{ 1983de2362d3Smrg return TRUE; 1984de2362d3Smrg} 1985de2362d3Smrg 1986de2362d3Smrgstatic const xf86OutputFuncsRec drmmode_output_funcs = { 1987de2362d3Smrg .dpms = drmmode_output_dpms, 1988de2362d3Smrg .create_resources = drmmode_output_create_resources, 1989de2362d3Smrg .set_property = drmmode_output_set_property, 1990de2362d3Smrg .get_property = drmmode_output_get_property, 1991de2362d3Smrg .detect = drmmode_output_detect, 1992de2362d3Smrg .mode_valid = drmmode_output_mode_valid, 1993de2362d3Smrg 1994de2362d3Smrg .get_modes = drmmode_output_get_modes, 1995de2362d3Smrg .destroy = drmmode_output_destroy 1996de2362d3Smrg}; 1997de2362d3Smrg 1998de2362d3Smrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown, 1999de2362d3Smrg SubPixelHorizontalRGB, 2000de2362d3Smrg SubPixelHorizontalBGR, 2001de2362d3Smrg SubPixelVerticalRGB, 2002de2362d3Smrg SubPixelVerticalBGR, 2003de2362d3Smrg SubPixelNone }; 2004de2362d3Smrg 2005de2362d3Smrgconst char *output_names[] = { "None", 2006de2362d3Smrg "VGA", 2007de2362d3Smrg "DVI", 2008de2362d3Smrg "DVI", 2009de2362d3Smrg "DVI", 2010de2362d3Smrg "Composite", 2011de2362d3Smrg "S-video", 2012de2362d3Smrg "LVDS", 2013de2362d3Smrg "CTV", 2014de2362d3Smrg "DIN", 2015de2362d3Smrg "DisplayPort", 2016de2362d3Smrg "HDMI", 2017de2362d3Smrg "HDMI", 2018de2362d3Smrg "TV", 2019de2362d3Smrg "eDP" 2020de2362d3Smrg}; 2021de2362d3Smrg 202218781e08Smrg#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0])) 202318781e08Smrg 202418781e08Smrgstatic xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id) 202518781e08Smrg{ 202618781e08Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 202718781e08Smrg int i; 202818781e08Smrg for (i = 0; i < xf86_config->num_output; i++) { 202918781e08Smrg xf86OutputPtr output = xf86_config->output[i]; 203018781e08Smrg drmmode_output_private_ptr drmmode_output; 203118781e08Smrg 203218781e08Smrg drmmode_output = output->driver_private; 203318781e08Smrg if (drmmode_output->output_id == id) 203418781e08Smrg return output; 203518781e08Smrg } 203618781e08Smrg return NULL; 203718781e08Smrg} 203818781e08Smrg 203918781e08Smrgstatic int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path) 204018781e08Smrg{ 204118781e08Smrg char *conn; 204218781e08Smrg char conn_id[5]; 204318781e08Smrg int id, len; 204418781e08Smrg char *blob_data; 204518781e08Smrg 204618781e08Smrg if (!path_blob) 204718781e08Smrg return -1; 204818781e08Smrg 204918781e08Smrg blob_data = path_blob->data; 205018781e08Smrg /* we only handle MST paths for now */ 205118781e08Smrg if (strncmp(blob_data, "mst:", 4)) 205218781e08Smrg return -1; 205318781e08Smrg 205418781e08Smrg conn = strchr(blob_data + 4, '-'); 205518781e08Smrg if (!conn) 205618781e08Smrg return -1; 205718781e08Smrg len = conn - (blob_data + 4); 205818781e08Smrg if (len + 1 > 5) 205918781e08Smrg return -1; 206018781e08Smrg memcpy(conn_id, blob_data + 4, len); 206118781e08Smrg conn_id[len] = '\0'; 206218781e08Smrg id = strtoul(conn_id, NULL, 10); 206318781e08Smrg 206418781e08Smrg *conn_base_id = id; 206518781e08Smrg 206618781e08Smrg *path = conn + 1; 206718781e08Smrg return 0; 206818781e08Smrg} 206918781e08Smrg 2070de2362d3Smrgstatic void 207118781e08Smrgdrmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name, 207218781e08Smrg drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi) 207318781e08Smrg{ 207418781e08Smrg xf86OutputPtr output; 207518781e08Smrg int conn_id; 207618781e08Smrg char *extra_path; 207718781e08Smrg 207818781e08Smrg output = NULL; 207918781e08Smrg if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0) 208018781e08Smrg output = find_output(pScrn, conn_id); 208118781e08Smrg if (output) { 208218781e08Smrg snprintf(name, 32, "%s-%s", output->name, extra_path); 208318781e08Smrg } else { 20848bf5c682Smrg if (koutput->connector_type >= NUM_OUTPUT_NAMES) { 208518781e08Smrg snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, 208618781e08Smrg koutput->connector_type_id - 1); 20878bf5c682Smrg } else if (pScrn->is_gpu) { 208818781e08Smrg snprintf(name, 32, "%s-%d-%d", 208918781e08Smrg output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, 209018781e08Smrg koutput->connector_type_id - 1); 20918bf5c682Smrg } else { 209218781e08Smrg /* need to do smart conversion here for compat with non-kms ATI driver */ 209318781e08Smrg if (koutput->connector_type_id == 1) { 209418781e08Smrg switch(koutput->connector_type) { 209518781e08Smrg case DRM_MODE_CONNECTOR_DVII: 209618781e08Smrg case DRM_MODE_CONNECTOR_DVID: 209718781e08Smrg case DRM_MODE_CONNECTOR_DVIA: 209818781e08Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi); 209918781e08Smrg (*num_dvi)++; 210018781e08Smrg break; 210118781e08Smrg case DRM_MODE_CONNECTOR_HDMIA: 210218781e08Smrg case DRM_MODE_CONNECTOR_HDMIB: 210318781e08Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi); 210418781e08Smrg (*num_hdmi)++; 210518781e08Smrg break; 210618781e08Smrg case DRM_MODE_CONNECTOR_VGA: 210718781e08Smrg case DRM_MODE_CONNECTOR_DisplayPort: 210818781e08Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], 210918781e08Smrg koutput->connector_type_id - 1); 211018781e08Smrg break; 211118781e08Smrg default: 211218781e08Smrg snprintf(name, 32, "%s", output_names[koutput->connector_type]); 211318781e08Smrg break; 211418781e08Smrg } 211518781e08Smrg } else { 211618781e08Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], 211718781e08Smrg koutput->connector_type_id - 1); 211818781e08Smrg } 211918781e08Smrg } 212018781e08Smrg } 212118781e08Smrg} 212218781e08Smrg 212318781e08Smrgstatic unsigned int 212418781e08Smrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic) 21250d16fef4Smrg{ 212618781e08Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 21278bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 2128de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 2129de2362d3Smrg xf86OutputPtr output; 2130de2362d3Smrg drmModeConnectorPtr koutput; 2131de2362d3Smrg drmModeEncoderPtr *kencoders = NULL; 2132de2362d3Smrg drmmode_output_private_ptr drmmode_output; 213318781e08Smrg drmModePropertyBlobPtr path_blob = NULL; 213439413783Smrg#if XF86_CRTC_VERSION >= 8 213539413783Smrg Bool nonDesktop = FALSE; 213639413783Smrg#endif 2137de2362d3Smrg char name[32]; 2138de2362d3Smrg int i; 2139de2362d3Smrg const char *s; 2140de2362d3Smrg 21418bf5c682Smrg koutput = drmModeGetConnector(pRADEONEnt->fd, mode_res->connectors[num]); 2142de2362d3Smrg if (!koutput) 214318781e08Smrg return 0; 214418781e08Smrg 21458bf5c682Smrg path_blob = koutput_get_prop_blob(pRADEONEnt->fd, koutput, "PATH"); 2146de2362d3Smrg 214739413783Smrg#if XF86_CRTC_VERSION >= 8 214839413783Smrg i = koutput_get_prop_idx(pRADEONEnt->fd, koutput, DRM_MODE_PROP_RANGE, 214939413783Smrg "non-desktop"); 215039413783Smrg if (i >= 0) 215139413783Smrg nonDesktop = koutput->prop_values[i] != 0; 215239413783Smrg#endif 215339413783Smrg 2154de2362d3Smrg kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); 2155de2362d3Smrg if (!kencoders) { 2156de2362d3Smrg goto out_free_encoders; 2157de2362d3Smrg } 2158de2362d3Smrg 2159de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) { 21608bf5c682Smrg kencoders[i] = drmModeGetEncoder(pRADEONEnt->fd, koutput->encoders[i]); 2161de2362d3Smrg if (!kencoders[i]) { 2162de2362d3Smrg goto out_free_encoders; 2163de2362d3Smrg } 2164de2362d3Smrg } 2165de2362d3Smrg 216618781e08Smrg drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi); 216718781e08Smrg if (path_blob) 216818781e08Smrg drmModeFreePropertyBlob(path_blob); 216918781e08Smrg 217018781e08Smrg if (path_blob && dynamic) { 217118781e08Smrg /* See if we have an output with this name already 217218781e08Smrg * and hook stuff up. 217318781e08Smrg */ 217418781e08Smrg for (i = 0; i < xf86_config->num_output; i++) { 217518781e08Smrg output = xf86_config->output[i]; 217618781e08Smrg 217718781e08Smrg if (strncmp(output->name, name, 32)) 217818781e08Smrg continue; 217918781e08Smrg 218018781e08Smrg drmmode_output = output->driver_private; 218118781e08Smrg drmmode_output->output_id = mode_res->connectors[num]; 218218781e08Smrg drmmode_output->mode_output = koutput; 218339413783Smrg#if XF86_CRTC_VERSION >= 8 218439413783Smrg output->non_desktop = nonDesktop; 218539413783Smrg#endif 218618781e08Smrg for (i = 0; i < koutput->count_encoders; i++) 218718781e08Smrg drmModeFreeEncoder(kencoders[i]); 218818781e08Smrg free(kencoders); 218918781e08Smrg return 0; 219018781e08Smrg } 2191de2362d3Smrg } 2192de2362d3Smrg 2193de2362d3Smrg if (xf86IsEntityShared(pScrn->entityList[0])) { 2194de2362d3Smrg if ((s = xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) { 2195de2362d3Smrg if (!RADEONZaphodStringMatches(pScrn, s, name)) 2196de2362d3Smrg goto out_free_encoders; 2197de2362d3Smrg } else { 2198446f62d6Smrg if (info->instance_id != num) 2199de2362d3Smrg goto out_free_encoders; 2200de2362d3Smrg } 2201de2362d3Smrg } 2202de2362d3Smrg 2203de2362d3Smrg output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name); 2204de2362d3Smrg if (!output) { 2205de2362d3Smrg goto out_free_encoders; 2206de2362d3Smrg } 2207de2362d3Smrg 2208de2362d3Smrg drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); 2209de2362d3Smrg if (!drmmode_output) { 2210de2362d3Smrg xf86OutputDestroy(output); 2211de2362d3Smrg goto out_free_encoders; 2212de2362d3Smrg } 2213de2362d3Smrg 221418781e08Smrg drmmode_output->output_id = mode_res->connectors[num]; 2215de2362d3Smrg drmmode_output->mode_output = koutput; 2216de2362d3Smrg drmmode_output->mode_encoders = kencoders; 2217de2362d3Smrg drmmode_output->drmmode = drmmode; 2218de2362d3Smrg output->mm_width = koutput->mmWidth; 2219de2362d3Smrg output->mm_height = koutput->mmHeight; 2220de2362d3Smrg 2221de2362d3Smrg output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 2222de2362d3Smrg output->interlaceAllowed = TRUE; 2223de2362d3Smrg output->doubleScanAllowed = TRUE; 2224de2362d3Smrg output->driver_private = drmmode_output; 222539413783Smrg#if XF86_CRTC_VERSION >= 8 222639413783Smrg output->non_desktop = nonDesktop; 222739413783Smrg#endif 2228de2362d3Smrg 2229de2362d3Smrg output->possible_crtcs = 0xffffffff; 2230de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) { 2231de2362d3Smrg output->possible_crtcs &= kencoders[i]->possible_crtcs; 2232de2362d3Smrg } 2233de2362d3Smrg /* work out the possible clones later */ 2234de2362d3Smrg output->possible_clones = 0; 2235de2362d3Smrg 22368bf5c682Smrg drmmode_output->dpms_enum_id = 22378bf5c682Smrg koutput_get_prop_id(pRADEONEnt->fd, koutput, DRM_MODE_PROP_ENUM, 22388bf5c682Smrg "DPMS"); 2239de2362d3Smrg 224018781e08Smrg if (dynamic) { 224118781e08Smrg output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output); 224218781e08Smrg drmmode_output_create_resources(output); 224318781e08Smrg } 224418781e08Smrg 224518781e08Smrg return 1; 2246de2362d3Smrgout_free_encoders: 2247de2362d3Smrg if (kencoders){ 2248de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) 2249de2362d3Smrg drmModeFreeEncoder(kencoders[i]); 2250de2362d3Smrg free(kencoders); 2251de2362d3Smrg } 2252de2362d3Smrg drmModeFreeConnector(koutput); 225318781e08Smrg return 0; 2254de2362d3Smrg} 2255de2362d3Smrg 2256de2362d3Smrguint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output) 2257de2362d3Smrg{ 2258de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private, clone_drmout; 2259de2362d3Smrg int i; 2260de2362d3Smrg xf86OutputPtr clone_output; 2261de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2262de2362d3Smrg int index_mask = 0; 2263de2362d3Smrg 2264de2362d3Smrg if (drmmode_output->enc_clone_mask == 0) 2265de2362d3Smrg return index_mask; 2266de2362d3Smrg 2267de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 2268de2362d3Smrg clone_output = xf86_config->output[i]; 2269de2362d3Smrg clone_drmout = clone_output->driver_private; 2270de2362d3Smrg if (output == clone_output) 2271de2362d3Smrg continue; 2272de2362d3Smrg 2273de2362d3Smrg if (clone_drmout->enc_mask == 0) 2274de2362d3Smrg continue; 2275de2362d3Smrg if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask) 2276de2362d3Smrg index_mask |= (1 << i); 2277de2362d3Smrg } 2278de2362d3Smrg return index_mask; 2279de2362d3Smrg} 2280de2362d3Smrg 2281de2362d3Smrg 2282de2362d3Smrgstatic void 228318781e08Smrgdrmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res) 2284de2362d3Smrg{ 2285de2362d3Smrg int i, j; 2286de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2287de2362d3Smrg 2288de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 2289de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 2290de2362d3Smrg drmmode_output_private_ptr drmmode_output; 2291de2362d3Smrg 2292de2362d3Smrg drmmode_output = output->driver_private; 2293de2362d3Smrg drmmode_output->enc_clone_mask = 0xff; 2294de2362d3Smrg /* and all the possible encoder clones for this output together */ 2295de2362d3Smrg for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) 2296de2362d3Smrg { 2297de2362d3Smrg int k; 229818781e08Smrg for (k = 0; k < mode_res->count_encoders; k++) { 229918781e08Smrg if (mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id) 2300de2362d3Smrg drmmode_output->enc_mask |= (1 << k); 2301de2362d3Smrg } 2302de2362d3Smrg 2303de2362d3Smrg drmmode_output->enc_clone_mask &= drmmode_output->mode_encoders[j]->possible_clones; 2304de2362d3Smrg } 2305de2362d3Smrg } 2306de2362d3Smrg 2307de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 2308de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 2309de2362d3Smrg output->possible_clones = find_clones(scrn, output); 2310de2362d3Smrg } 2311de2362d3Smrg} 2312de2362d3Smrg 2313de2362d3Smrg/* returns height alignment in pixels */ 2314de2362d3Smrgint drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling) 2315de2362d3Smrg{ 2316de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 2317de2362d3Smrg int height_align = 1; 2318de2362d3Smrg 2319de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 2320de2362d3Smrg if (tiling & RADEON_TILING_MACRO) 2321de2362d3Smrg height_align = info->num_channels * 8; 2322de2362d3Smrg else if (tiling & RADEON_TILING_MICRO) 2323de2362d3Smrg height_align = 8; 2324de2362d3Smrg else 2325de2362d3Smrg height_align = 8; 2326de2362d3Smrg } else { 232718781e08Smrg if (tiling & RADEON_TILING_MICRO_SQUARE) 232818781e08Smrg height_align = 32; 232918781e08Smrg else if (tiling) 2330de2362d3Smrg height_align = 16; 2331de2362d3Smrg else 2332de2362d3Smrg height_align = 1; 2333de2362d3Smrg } 2334de2362d3Smrg return height_align; 2335de2362d3Smrg} 2336de2362d3Smrg 2337de2362d3Smrg/* returns pitch alignment in pixels */ 2338de2362d3Smrgint drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling) 2339de2362d3Smrg{ 2340de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 2341de2362d3Smrg int pitch_align = 1; 2342de2362d3Smrg 2343de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 2344de2362d3Smrg if (tiling & RADEON_TILING_MACRO) { 2345de2362d3Smrg /* general surface requirements */ 2346de2362d3Smrg pitch_align = MAX(info->num_banks, 2347de2362d3Smrg (((info->group_bytes / 8) / bpe) * info->num_banks)) * 8; 2348de2362d3Smrg /* further restrictions for scanout */ 2349de2362d3Smrg pitch_align = MAX(info->num_banks * 8, pitch_align); 2350de2362d3Smrg } else if (tiling & RADEON_TILING_MICRO) { 2351de2362d3Smrg /* general surface requirements */ 2352de2362d3Smrg pitch_align = MAX(8, (info->group_bytes / (8 * bpe))); 2353de2362d3Smrg /* further restrictions for scanout */ 2354de2362d3Smrg pitch_align = MAX(info->group_bytes / bpe, pitch_align); 2355de2362d3Smrg } else { 2356de2362d3Smrg if (info->have_tiling_info) 2357de2362d3Smrg /* linear aligned requirements */ 2358de2362d3Smrg pitch_align = MAX(64, info->group_bytes / bpe); 2359de2362d3Smrg else 2360de2362d3Smrg /* default to 512 elements if we don't know the real 2361de2362d3Smrg * group size otherwise the kernel may reject the CS 2362de2362d3Smrg * if the group sizes don't match as the pitch won't 2363de2362d3Smrg * be aligned properly. 2364de2362d3Smrg */ 2365de2362d3Smrg pitch_align = 512; 2366de2362d3Smrg } 2367de2362d3Smrg } else { 2368de2362d3Smrg /* general surface requirements */ 2369de2362d3Smrg if (tiling) 2370de2362d3Smrg pitch_align = 256 / bpe; 2371de2362d3Smrg else 2372de2362d3Smrg pitch_align = 64; 2373de2362d3Smrg } 2374de2362d3Smrg return pitch_align; 2375de2362d3Smrg} 2376de2362d3Smrg 2377de2362d3Smrg/* returns base alignment in bytes */ 2378de2362d3Smrgint drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling) 2379de2362d3Smrg{ 2380de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 2381de2362d3Smrg int pixel_align = drmmode_get_pitch_align(scrn, bpe, tiling); 2382de2362d3Smrg int height_align = drmmode_get_height_align(scrn, tiling); 2383de2362d3Smrg int base_align = RADEON_GPU_PAGE_SIZE; 2384de2362d3Smrg 2385de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 2386de2362d3Smrg if (tiling & RADEON_TILING_MACRO) 2387de2362d3Smrg base_align = MAX(info->num_banks * info->num_channels * 8 * 8 * bpe, 2388de2362d3Smrg pixel_align * bpe * height_align); 2389de2362d3Smrg else { 2390de2362d3Smrg if (info->have_tiling_info) 2391de2362d3Smrg base_align = info->group_bytes; 2392de2362d3Smrg else 2393de2362d3Smrg /* default to 512 if we don't know the real 2394de2362d3Smrg * group size otherwise the kernel may reject the CS 2395de2362d3Smrg * if the group sizes don't match as the base won't 2396de2362d3Smrg * be aligned properly. 2397de2362d3Smrg */ 2398de2362d3Smrg base_align = 512; 2399de2362d3Smrg } 2400de2362d3Smrg } 2401de2362d3Smrg return base_align; 2402de2362d3Smrg} 2403de2362d3Smrg 2404de2362d3Smrgstatic Bool 2405de2362d3Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) 2406de2362d3Smrg{ 2407de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2408de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 240939413783Smrg struct radeon_buffer *old_front = NULL; 2410de2362d3Smrg ScreenPtr screen = xf86ScrnToScreen(scrn); 2411de2362d3Smrg int i, pitch, old_width, old_height, old_pitch; 241239413783Smrg int usage = CREATE_PIXMAP_USAGE_BACKING_PIXMAP; 241318781e08Smrg int cpp = info->pixel_bytes; 241439413783Smrg uint32_t tiling_flags; 2415de2362d3Smrg PixmapPtr ppix = screen->GetScreenPixmap(screen); 2416de2362d3Smrg void *fb_shadow; 2417de2362d3Smrg 2418de2362d3Smrg if (scrn->virtualX == width && scrn->virtualY == height) 2419de2362d3Smrg return TRUE; 2420de2362d3Smrg 242139413783Smrg if (width > xf86_config->maxWidth || height > xf86_config->maxHeight) { 242239413783Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 242339413783Smrg "Xorg tried resizing screen to %dx%d, but maximum " 242439413783Smrg "supported is %dx%d\n", width, height, 242539413783Smrg xf86_config->maxWidth, xf86_config->maxHeight); 242639413783Smrg return FALSE; 2427de2362d3Smrg } 2428de2362d3Smrg 242939413783Smrg if (info->allowColorTiling && !info->shadow_primary) { 243039413783Smrg if (info->ChipFamily < CHIP_FAMILY_R600 || info->allowColorTiling2D) 243139413783Smrg usage |= RADEON_CREATE_PIXMAP_TILING_MACRO; 243239413783Smrg else 243339413783Smrg usage |= RADEON_CREATE_PIXMAP_TILING_MICRO; 2434de2362d3Smrg } 2435de2362d3Smrg 243639413783Smrg xf86DrvMsg(scrn->scrnIndex, X_INFO, "Allocate new frame buffer %dx%d\n", 243739413783Smrg width, height); 2438de2362d3Smrg 2439de2362d3Smrg old_width = scrn->virtualX; 2440de2362d3Smrg old_height = scrn->virtualY; 2441de2362d3Smrg old_pitch = scrn->displayWidth; 244239413783Smrg old_front = info->front_buffer; 2443de2362d3Smrg 2444de2362d3Smrg scrn->virtualX = width; 2445de2362d3Smrg scrn->virtualY = height; 2446de2362d3Smrg 244739413783Smrg info->front_buffer = radeon_alloc_pixmap_bo(scrn, scrn->virtualX, 244839413783Smrg scrn->virtualY, scrn->depth, 244939413783Smrg usage, scrn->bitsPerPixel, 245039413783Smrg &pitch, 245139413783Smrg &info->front_surface, 245239413783Smrg &tiling_flags); 245339413783Smrg if (!info->front_buffer) 2454de2362d3Smrg goto fail; 2455de2362d3Smrg 245639413783Smrg scrn->displayWidth = pitch / cpp; 245739413783Smrg 245839413783Smrg if (!info->use_glamor) { 2459de2362d3Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN 246039413783Smrg switch (cpp) { 246139413783Smrg case 4: 246239413783Smrg tiling_flags |= RADEON_TILING_SWAP_32BIT; 246339413783Smrg break; 246439413783Smrg case 2: 246539413783Smrg tiling_flags |= RADEON_TILING_SWAP_16BIT; 246639413783Smrg break; 246739413783Smrg } 246839413783Smrg if (info->ChipFamily < CHIP_FAMILY_R600 && 246939413783Smrg info->r600_shadow_fb && tiling_flags) 247039413783Smrg tiling_flags |= RADEON_TILING_SURFACE; 2471de2362d3Smrg#endif 247239413783Smrg if (tiling_flags) 247339413783Smrg radeon_bo_set_tiling(info->front_buffer->bo.radeon, tiling_flags, pitch); 247439413783Smrg } 2475de2362d3Smrg 2476de2362d3Smrg if (!info->r600_shadow_fb) { 247739413783Smrg if (info->surf_man && !info->use_glamor) 247839413783Smrg *radeon_get_pixmap_surface(ppix) = info->front_surface; 2479de2362d3Smrg screen->ModifyPixmapHeader(ppix, 2480de2362d3Smrg width, height, -1, -1, pitch, NULL); 2481de2362d3Smrg } else { 248239413783Smrg if (radeon_bo_map(info->front_buffer->bo.radeon, 1)) 2483de2362d3Smrg goto fail; 248439413783Smrg fb_shadow = calloc(1, pitch * scrn->virtualY); 248539413783Smrg if (!fb_shadow) 2486de2362d3Smrg goto fail; 2487de2362d3Smrg free(info->fb_shadow); 2488de2362d3Smrg info->fb_shadow = fb_shadow; 2489de2362d3Smrg screen->ModifyPixmapHeader(ppix, 2490de2362d3Smrg width, height, -1, -1, pitch, 2491de2362d3Smrg info->fb_shadow); 2492de2362d3Smrg } 249318781e08Smrg 249418781e08Smrg if (info->use_glamor) 249518781e08Smrg radeon_glamor_create_screen_resources(scrn->pScreen); 249618781e08Smrg 249718781e08Smrg if (!info->r600_shadow_fb) { 249839413783Smrg if (!radeon_set_pixmap_bo(ppix, info->front_buffer)) 249918781e08Smrg goto fail; 250018781e08Smrg } 250118781e08Smrg 25028bf5c682Smrg radeon_pixmap_clear(ppix); 250339413783Smrg radeon_finish(scrn, info->front_buffer); 25040d16fef4Smrg 2505de2362d3Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 2506de2362d3Smrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 2507de2362d3Smrg 2508de2362d3Smrg if (!crtc->enabled) 2509de2362d3Smrg continue; 2510de2362d3Smrg 2511de2362d3Smrg drmmode_set_mode_major(crtc, &crtc->mode, 2512de2362d3Smrg crtc->rotation, crtc->x, crtc->y); 2513de2362d3Smrg } 2514de2362d3Smrg 251539413783Smrg radeon_buffer_unref(&old_front); 2516de2362d3Smrg 251739413783Smrg radeon_kms_update_vram_limit(scrn, pitch * scrn->virtualY); 2518de2362d3Smrg return TRUE; 2519de2362d3Smrg 2520de2362d3Smrg fail: 252139413783Smrg radeon_buffer_unref(&info->front_buffer); 252239413783Smrg info->front_buffer = old_front; 2523de2362d3Smrg scrn->virtualX = old_width; 2524de2362d3Smrg scrn->virtualY = old_height; 2525de2362d3Smrg scrn->displayWidth = old_pitch; 2526de2362d3Smrg 2527de2362d3Smrg return FALSE; 2528de2362d3Smrg} 2529de2362d3Smrg 253039413783Smrgstatic void 253139413783Smrgdrmmode_validate_leases(ScrnInfoPtr scrn) 253239413783Smrg{ 253339413783Smrg#ifdef XF86_LEASE_VERSION 253439413783Smrg ScreenPtr screen = scrn->pScreen; 253539413783Smrg rrScrPrivPtr scr_priv = rrGetScrPriv(screen); 253639413783Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 253739413783Smrg drmModeLesseeListPtr lessees; 253839413783Smrg RRLeasePtr lease, next; 253939413783Smrg int l; 254039413783Smrg 254139413783Smrg /* We can't talk to the kernel about leases when VT switched */ 254239413783Smrg if (!scrn->vtSema) 254339413783Smrg return; 254439413783Smrg 254539413783Smrg lessees = drmModeListLessees(pRADEONEnt->fd); 254639413783Smrg if (!lessees) 254739413783Smrg return; 254839413783Smrg 254939413783Smrg xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) { 255039413783Smrg drmmode_lease_private_ptr lease_private = lease->devPrivate; 255139413783Smrg 255239413783Smrg for (l = 0; l < lessees->count; l++) { 255339413783Smrg if (lessees->lessees[l] == lease_private->lessee_id) 255439413783Smrg break; 255539413783Smrg } 255639413783Smrg 255739413783Smrg /* check to see if the lease has gone away */ 255839413783Smrg if (l == lessees->count) { 255939413783Smrg free(lease_private); 256039413783Smrg lease->devPrivate = NULL; 256139413783Smrg xf86CrtcLeaseTerminated(lease); 256239413783Smrg } 256339413783Smrg } 256439413783Smrg 256539413783Smrg free(lessees); 256639413783Smrg#endif 256739413783Smrg} 256839413783Smrg 256939413783Smrg#ifdef XF86_LEASE_VERSION 257039413783Smrg 257139413783Smrgstatic int 257239413783Smrgdrmmode_create_lease(RRLeasePtr lease, int *fd) 257339413783Smrg{ 257439413783Smrg ScreenPtr screen = lease->screen; 257539413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 257639413783Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 257739413783Smrg drmmode_lease_private_ptr lease_private; 257839413783Smrg int noutput = lease->numOutputs; 257939413783Smrg int ncrtc = lease->numCrtcs; 258039413783Smrg uint32_t *objects; 258139413783Smrg size_t nobjects; 258239413783Smrg int lease_fd; 258339413783Smrg int c, o; 258439413783Smrg int i; 258539413783Smrg 258639413783Smrg nobjects = ncrtc + noutput; 258739413783Smrg if (nobjects == 0 || nobjects > (SIZE_MAX / 4) || 258839413783Smrg ncrtc > (SIZE_MAX - noutput)) 258939413783Smrg return BadValue; 259039413783Smrg 259139413783Smrg lease_private = calloc(1, sizeof (drmmode_lease_private_rec)); 259239413783Smrg if (!lease_private) 259339413783Smrg return BadAlloc; 259439413783Smrg 259539413783Smrg objects = malloc(nobjects * 4); 259639413783Smrg if (!objects) { 259739413783Smrg free(lease_private); 259839413783Smrg return BadAlloc; 259939413783Smrg } 260039413783Smrg 260139413783Smrg i = 0; 260239413783Smrg 260339413783Smrg /* Add CRTC ids */ 260439413783Smrg for (c = 0; c < ncrtc; c++) { 260539413783Smrg xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate; 260639413783Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 260739413783Smrg 260839413783Smrg objects[i++] = drmmode_crtc->mode_crtc->crtc_id; 260939413783Smrg } 261039413783Smrg 261139413783Smrg /* Add connector ids */ 261239413783Smrg for (o = 0; o < noutput; o++) { 261339413783Smrg xf86OutputPtr output = lease->outputs[o]->devPrivate; 261439413783Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 261539413783Smrg 261639413783Smrg objects[i++] = drmmode_output->mode_output->connector_id; 261739413783Smrg } 261839413783Smrg 261939413783Smrg /* call kernel to create lease */ 262039413783Smrg assert (i == nobjects); 262139413783Smrg 262239413783Smrg lease_fd = drmModeCreateLease(pRADEONEnt->fd, objects, nobjects, 0, 262339413783Smrg &lease_private->lessee_id); 262439413783Smrg 262539413783Smrg free(objects); 262639413783Smrg 262739413783Smrg if (lease_fd < 0) { 262839413783Smrg free(lease_private); 262939413783Smrg return BadMatch; 263039413783Smrg } 263139413783Smrg 263239413783Smrg lease->devPrivate = lease_private; 263339413783Smrg 263439413783Smrg xf86CrtcLeaseStarted(lease); 263539413783Smrg 263639413783Smrg *fd = lease_fd; 263739413783Smrg return Success; 263839413783Smrg} 263939413783Smrg 264039413783Smrgstatic void 264139413783Smrgdrmmode_terminate_lease(RRLeasePtr lease) 264239413783Smrg{ 264339413783Smrg drmmode_lease_private_ptr lease_private = lease->devPrivate; 264439413783Smrg ScreenPtr screen = lease->screen; 264539413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 264639413783Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 264739413783Smrg 264839413783Smrg if (drmModeRevokeLease(pRADEONEnt->fd, lease_private->lessee_id) == 0) { 264939413783Smrg free(lease_private); 265039413783Smrg lease->devPrivate = NULL; 265139413783Smrg xf86CrtcLeaseTerminated(lease); 265239413783Smrg } 265339413783Smrg} 265439413783Smrg 265539413783Smrg#endif // XF86_LEASE_VERSION 265639413783Smrg 2657de2362d3Smrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { 265839413783Smrg .resize = drmmode_xf86crtc_resize, 265939413783Smrg#ifdef XF86_LEASE_VERSION 266039413783Smrg .create_lease = drmmode_create_lease, 266139413783Smrg .terminate_lease = drmmode_terminate_lease 266239413783Smrg#endif 2663de2362d3Smrg}; 2664de2362d3Smrg 2665de2362d3Smrgstatic void 266618781e08Smrgdrmmode_flip_abort(xf86CrtcPtr crtc, void *event_data) 2667de2362d3Smrg{ 26688bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 26698bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 267018781e08Smrg drmmode_flipdata_ptr flipdata = event_data; 267139413783Smrg int crtc_id = drmmode_get_crtc_id(crtc); 267239413783Smrg struct drmmode_fb **fb = &flipdata->fb[crtc_id]; 267339413783Smrg 267439413783Smrg if (drmmode_crtc->flip_pending == *fb) { 267539413783Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->flip_pending, 267639413783Smrg NULL); 267739413783Smrg } 267839413783Smrg drmmode_fb_reference(pRADEONEnt->fd, fb, NULL); 267918781e08Smrg 268018781e08Smrg if (--flipdata->flip_count == 0) { 268118781e08Smrg if (!flipdata->fe_crtc) 268218781e08Smrg flipdata->fe_crtc = crtc; 268318781e08Smrg flipdata->abort(flipdata->fe_crtc, flipdata->event_data); 268418781e08Smrg free(flipdata); 268518781e08Smrg } 2686de2362d3Smrg} 2687de2362d3Smrg 2688de2362d3Smrgstatic void 268918781e08Smrgdrmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data) 2690de2362d3Smrg{ 26918bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 26928bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 269318781e08Smrg drmmode_flipdata_ptr flipdata = event_data; 269439413783Smrg int crtc_id = drmmode_get_crtc_id(crtc); 269539413783Smrg struct drmmode_fb **fb = &flipdata->fb[crtc_id]; 2696de2362d3Smrg 2697de2362d3Smrg /* Is this the event whose info shall be delivered to higher level? */ 269818781e08Smrg if (crtc == flipdata->fe_crtc) { 2699de2362d3Smrg /* Yes: Cache msc, ust for later delivery. */ 2700de2362d3Smrg flipdata->fe_frame = frame; 270118781e08Smrg flipdata->fe_usec = usec; 2702de2362d3Smrg } 2703de2362d3Smrg 2704446f62d6Smrg if (*fb) { 2705446f62d6Smrg if (drmmode_crtc->flip_pending == *fb) { 2706446f62d6Smrg drmmode_fb_reference(pRADEONEnt->fd, 2707446f62d6Smrg &drmmode_crtc->flip_pending, NULL); 2708446f62d6Smrg } 2709446f62d6Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, *fb); 2710446f62d6Smrg drmmode_fb_reference(pRADEONEnt->fd, fb, NULL); 27118bf5c682Smrg } 27128bf5c682Smrg 271318781e08Smrg if (--flipdata->flip_count == 0) { 271418781e08Smrg /* Deliver MSC & UST from reference/current CRTC to flip event 271518781e08Smrg * handler 271618781e08Smrg */ 271718781e08Smrg if (flipdata->fe_crtc) 271818781e08Smrg flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame, 271918781e08Smrg flipdata->fe_usec, flipdata->event_data); 272018781e08Smrg else 272118781e08Smrg flipdata->handler(crtc, frame, usec, flipdata->event_data); 2722de2362d3Smrg 272318781e08Smrg free(flipdata); 272418781e08Smrg } 2725de2362d3Smrg} 2726de2362d3Smrg 2727de2362d3Smrg 272818781e08Smrg#if HAVE_NOTIFY_FD 272918781e08Smrgstatic void 273018781e08Smrgdrm_notify_fd(int fd, int ready, void *data) 273118781e08Smrg#else 2732de2362d3Smrgstatic void 2733de2362d3Smrgdrm_wakeup_handler(pointer data, int err, pointer p) 273418781e08Smrg#endif 2735de2362d3Smrg{ 273639413783Smrg drmmode_ptr drmmode = data; 273739413783Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(drmmode->scrn); 27388bf5c682Smrg 273918781e08Smrg#if !HAVE_NOTIFY_FD 2740de2362d3Smrg fd_set *read_mask = p; 2741de2362d3Smrg 27428bf5c682Smrg if (err >= 0 && FD_ISSET(pRADEONEnt->fd, read_mask)) 274318781e08Smrg#endif 274418781e08Smrg { 274539413783Smrg radeon_drm_handle_event(pRADEONEnt->fd, &drmmode->event_context); 2746de2362d3Smrg } 2747de2362d3Smrg} 2748de2362d3Smrg 27498bf5c682Smrgstatic Bool drmmode_probe_page_flip_target(RADEONEntPtr pRADEONEnt) 27503ed65abbSmrg{ 27513ed65abbSmrg#ifdef DRM_CAP_PAGE_FLIP_TARGET 27523ed65abbSmrg uint64_t cap_value; 27533ed65abbSmrg 27548bf5c682Smrg return drmGetCap(pRADEONEnt->fd, DRM_CAP_PAGE_FLIP_TARGET, 27553ed65abbSmrg &cap_value) == 0 && cap_value != 0; 27563ed65abbSmrg#else 27573ed65abbSmrg return FALSE; 27583ed65abbSmrg#endif 27593ed65abbSmrg} 27603ed65abbSmrg 27613ed65abbSmrgstatic int 27628bf5c682Smrgdrmmode_page_flip(RADEONEntPtr pRADEONEnt, 27638bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc, int fb_id, 27643ed65abbSmrg uint32_t flags, uintptr_t drm_queue_seq) 27653ed65abbSmrg{ 27663ed65abbSmrg flags |= DRM_MODE_PAGE_FLIP_EVENT; 27678bf5c682Smrg return drmModePageFlip(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 27683ed65abbSmrg fb_id, flags, (void*)drm_queue_seq); 27693ed65abbSmrg} 27703ed65abbSmrg 27713ed65abbSmrgint 27723ed65abbSmrgdrmmode_page_flip_target_absolute(RADEONEntPtr pRADEONEnt, 27733ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc, 27743ed65abbSmrg int fb_id, uint32_t flags, 27753ed65abbSmrg uintptr_t drm_queue_seq, uint32_t target_msc) 27763ed65abbSmrg{ 27773ed65abbSmrg#ifdef DRM_MODE_PAGE_FLIP_TARGET 27783ed65abbSmrg if (pRADEONEnt->has_page_flip_target) { 27793ed65abbSmrg flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE; 27808bf5c682Smrg return drmModePageFlipTarget(pRADEONEnt->fd, 27813ed65abbSmrg drmmode_crtc->mode_crtc->crtc_id, 27823ed65abbSmrg fb_id, flags, (void*)drm_queue_seq, 27833ed65abbSmrg target_msc); 27843ed65abbSmrg } 27853ed65abbSmrg#endif 27863ed65abbSmrg 27878bf5c682Smrg return drmmode_page_flip(pRADEONEnt, drmmode_crtc, fb_id, flags, 27888bf5c682Smrg drm_queue_seq); 27893ed65abbSmrg} 27903ed65abbSmrg 27913ed65abbSmrgint 27923ed65abbSmrgdrmmode_page_flip_target_relative(RADEONEntPtr pRADEONEnt, 27933ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc, 27943ed65abbSmrg int fb_id, uint32_t flags, 27953ed65abbSmrg uintptr_t drm_queue_seq, uint32_t target_msc) 27963ed65abbSmrg{ 27973ed65abbSmrg#ifdef DRM_MODE_PAGE_FLIP_TARGET 27983ed65abbSmrg if (pRADEONEnt->has_page_flip_target) { 27993ed65abbSmrg flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE; 28008bf5c682Smrg return drmModePageFlipTarget(pRADEONEnt->fd, 28013ed65abbSmrg drmmode_crtc->mode_crtc->crtc_id, 28023ed65abbSmrg fb_id, flags, (void*)drm_queue_seq, 28033ed65abbSmrg target_msc); 28043ed65abbSmrg } 28053ed65abbSmrg#endif 28063ed65abbSmrg 28078bf5c682Smrg return drmmode_page_flip(pRADEONEnt, drmmode_crtc, fb_id, flags, 28088bf5c682Smrg drm_queue_seq); 28093ed65abbSmrg} 28103ed65abbSmrg 2811de2362d3SmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) 2812de2362d3Smrg{ 281318781e08Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 281418781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 2815de2362d3Smrg int i, num_dvi = 0, num_hdmi = 0; 281618781e08Smrg drmModeResPtr mode_res; 281718781e08Smrg unsigned int crtcs_needed = 0; 2818446f62d6Smrg unsigned int crtcs_got = 0; 281918781e08Smrg char *bus_id_string, *provider_name; 2820de2362d3Smrg 2821de2362d3Smrg xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); 2822de2362d3Smrg 2823de2362d3Smrg drmmode->scrn = pScrn; 28248bf5c682Smrg mode_res = drmModeGetResources(pRADEONEnt->fd); 282518781e08Smrg if (!mode_res) 2826de2362d3Smrg return FALSE; 2827de2362d3Smrg 282818781e08Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 282918781e08Smrg "Initializing outputs ...\n"); 283018781e08Smrg for (i = 0; i < mode_res->count_connectors; i++) 283118781e08Smrg crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, 283218781e08Smrg i, &num_dvi, &num_hdmi, 0); 283318781e08Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 283418781e08Smrg "%d crtcs needed for screen.\n", crtcs_needed); 283518781e08Smrg 28368bf5c682Smrg /* Need per-screen drmmode_crtc_funcs, based on our global template, 28378bf5c682Smrg * so we can disable some functions, depending on screen settings. 28388bf5c682Smrg */ 28398bf5c682Smrg info->drmmode_crtc_funcs = drmmode_crtc_funcs; 28408bf5c682Smrg 284118781e08Smrg if (info->r600_shadow_fb) { 284218781e08Smrg /* Rotation requires hardware acceleration */ 28438bf5c682Smrg info->drmmode_crtc_funcs.shadow_allocate = NULL; 28448bf5c682Smrg info->drmmode_crtc_funcs.shadow_create = NULL; 28458bf5c682Smrg info->drmmode_crtc_funcs.shadow_destroy = NULL; 284618781e08Smrg } 284718781e08Smrg 28488bf5c682Smrg /* Hw gamma lut's are currently bypassed by the hw at color depth 30, 28498bf5c682Smrg * so spare the server the effort to compute and update the cluts. 28508bf5c682Smrg */ 28518bf5c682Smrg if (pScrn->depth == 30) 28528bf5c682Smrg info->drmmode_crtc_funcs.gamma_set = NULL; 28538bf5c682Smrg 285418781e08Smrg drmmode->count_crtcs = mode_res->count_crtcs; 285518781e08Smrg xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, mode_res->max_height); 285618781e08Smrg 2857446f62d6Smrg for (i = 0; i < mode_res->count_crtcs; i++) { 285818781e08Smrg if (!xf86IsEntityShared(pScrn->entityList[0]) || 2859446f62d6Smrg (crtcs_got < crtcs_needed && 2860446f62d6Smrg !(pRADEONEnt->assigned_crtcs & (1 << i)))) 2861446f62d6Smrg crtcs_got += drmmode_crtc_init(pScrn, drmmode, mode_res, i); 2862446f62d6Smrg } 2863de2362d3Smrg 286418781e08Smrg /* All ZaphodHeads outputs provided with matching crtcs? */ 2865446f62d6Smrg if (crtcs_got < crtcs_needed) { 2866446f62d6Smrg if (crtcs_got == 0) { 2867446f62d6Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 2868446f62d6Smrg "No ZaphodHeads CRTC available, needed %u\n", 2869446f62d6Smrg crtcs_needed); 2870446f62d6Smrg return FALSE; 2871446f62d6Smrg } 2872446f62d6Smrg 287318781e08Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 287418781e08Smrg "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n", 287518781e08Smrg crtcs_needed); 2876446f62d6Smrg } 2877de2362d3Smrg 2878de2362d3Smrg /* workout clones */ 287918781e08Smrg drmmode_clones_init(pScrn, drmmode, mode_res); 288018781e08Smrg 288118781e08Smrg bus_id_string = DRICreatePCIBusID(info->PciInfo); 288218781e08Smrg XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, bus_id_string); 288318781e08Smrg free(bus_id_string); 288418781e08Smrg xf86ProviderSetup(pScrn, NULL, provider_name); 288518781e08Smrg free(provider_name); 2886de2362d3Smrg 2887de2362d3Smrg xf86InitialConfiguration(pScrn, TRUE); 2888de2362d3Smrg 28898bf5c682Smrg pRADEONEnt->has_page_flip_target = drmmode_probe_page_flip_target(pRADEONEnt); 28903ed65abbSmrg 289118781e08Smrg drmModeFreeResources(mode_res); 2892de2362d3Smrg return TRUE; 2893de2362d3Smrg} 2894de2362d3Smrg 2895de2362d3Smrgvoid drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 2896de2362d3Smrg{ 2897de2362d3Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 2898de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 2899de2362d3Smrg 290018781e08Smrg if (info->dri2.pKernelDRMVersion->version_minor < 4) 290118781e08Smrg return; 290218781e08Smrg 290318781e08Smrg info->drmmode_inited = TRUE; 290418781e08Smrg if (pRADEONEnt->fd_wakeup_registered != serverGeneration) { 290518781e08Smrg#if HAVE_NOTIFY_FD 290639413783Smrg SetNotifyFd(pRADEONEnt->fd, drm_notify_fd, X_NOTIFY_READ, 290739413783Smrg &info->drmmode); 290818781e08Smrg#else 29098bf5c682Smrg AddGeneralSocket(pRADEONEnt->fd); 2910de2362d3Smrg RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, 291139413783Smrg drm_wakeup_handler, 291239413783Smrg &info->drmmode); 291318781e08Smrg#endif 2914de2362d3Smrg pRADEONEnt->fd_wakeup_registered = serverGeneration; 291518781e08Smrg pRADEONEnt->fd_wakeup_ref = 1; 291618781e08Smrg } else 291718781e08Smrg pRADEONEnt->fd_wakeup_ref++; 291818781e08Smrg} 291918781e08Smrg 292018781e08Smrgvoid drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 292118781e08Smrg{ 292218781e08Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 292318781e08Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 292418781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 292518781e08Smrg int c; 292618781e08Smrg 292718781e08Smrg if (info->dri2.pKernelDRMVersion->version_minor < 4 || !info->drmmode_inited) 292818781e08Smrg return; 292918781e08Smrg 2930446f62d6Smrg for (c = 0; c < config->num_crtc; c++) 2931446f62d6Smrg drmmode_crtc_scanout_free(config->crtc[c]); 2932446f62d6Smrg 293318781e08Smrg if (pRADEONEnt->fd_wakeup_registered == serverGeneration && 293418781e08Smrg !--pRADEONEnt->fd_wakeup_ref) { 293518781e08Smrg#if HAVE_NOTIFY_FD 29368bf5c682Smrg RemoveNotifyFd(pRADEONEnt->fd); 293718781e08Smrg#else 29388bf5c682Smrg RemoveGeneralSocket(pRADEONEnt->fd); 293918781e08Smrg RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, 29408bf5c682Smrg drm_wakeup_handler, pScrn); 294118781e08Smrg#endif 294218781e08Smrg } 2943de2362d3Smrg} 2944de2362d3Smrg 294518781e08Smrg 2946de2362d3SmrgBool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, struct radeon_bo_manager *bufmgr) 2947de2362d3Smrg{ 2948de2362d3Smrg drmmode->bufmgr = bufmgr; 2949de2362d3Smrg return TRUE; 2950de2362d3Smrg} 2951de2362d3Smrg 2952de2362d3Smrg 29538bf5c682Smrgstatic void drmmode_sprite_do_set_cursor(struct radeon_device_priv *device_priv, 29548bf5c682Smrg ScrnInfoPtr scrn, int x, int y) 29558bf5c682Smrg{ 29568bf5c682Smrg RADEONInfoPtr info = RADEONPTR(scrn); 29578bf5c682Smrg CursorPtr cursor = device_priv->cursor; 29588bf5c682Smrg Bool sprite_visible = device_priv->sprite_visible; 29598bf5c682Smrg 29608bf5c682Smrg if (cursor) { 29618bf5c682Smrg x -= cursor->bits->xhot; 29628bf5c682Smrg y -= cursor->bits->yhot; 29638bf5c682Smrg 29648bf5c682Smrg device_priv->sprite_visible = 29658bf5c682Smrg x < scrn->virtualX && y < scrn->virtualY && 29668bf5c682Smrg (x + cursor->bits->width > 0) && 29678bf5c682Smrg (y + cursor->bits->height > 0); 29688bf5c682Smrg } else { 29698bf5c682Smrg device_priv->sprite_visible = FALSE; 29708bf5c682Smrg } 29718bf5c682Smrg 29728bf5c682Smrg info->sprites_visible += device_priv->sprite_visible - sprite_visible; 29738bf5c682Smrg} 29748bf5c682Smrg 297539413783Smrgstatic void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 297639413783Smrg CursorPtr pCursor, int x, int y) 29778bf5c682Smrg{ 29788bf5c682Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 29798bf5c682Smrg RADEONInfoPtr info = RADEONPTR(scrn); 29808bf5c682Smrg struct radeon_device_priv *device_priv = 29818bf5c682Smrg dixLookupScreenPrivate(&pDev->devPrivates, 29828bf5c682Smrg &radeon_device_private_key, pScreen); 29838bf5c682Smrg 29848bf5c682Smrg device_priv->cursor = pCursor; 29858bf5c682Smrg drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 29868bf5c682Smrg 298739413783Smrg info->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y); 29888bf5c682Smrg} 29898bf5c682Smrg 299039413783Smrgstatic void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 299139413783Smrg int x, int y) 29928bf5c682Smrg{ 29938bf5c682Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 29948bf5c682Smrg RADEONInfoPtr info = RADEONPTR(scrn); 29958bf5c682Smrg struct radeon_device_priv *device_priv = 29968bf5c682Smrg dixLookupScreenPrivate(&pDev->devPrivates, 29978bf5c682Smrg &radeon_device_private_key, pScreen); 29988bf5c682Smrg 29998bf5c682Smrg drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 30008bf5c682Smrg 300139413783Smrg info->SpriteFuncs->MoveCursor(pDev, pScreen, x, y); 300239413783Smrg} 300339413783Smrg 300439413783Smrgstatic Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev, 300539413783Smrg ScreenPtr pScreen, 300639413783Smrg CursorPtr pCursor) 300739413783Smrg{ 300839413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 300939413783Smrg RADEONInfoPtr info = RADEONPTR(scrn); 301039413783Smrg 301139413783Smrg return info->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor); 301239413783Smrg} 301339413783Smrg 301439413783Smrgstatic Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev, 301539413783Smrg ScreenPtr pScreen, 301639413783Smrg CursorPtr pCursor) 301739413783Smrg{ 301839413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 301939413783Smrg RADEONInfoPtr info = RADEONPTR(scrn); 302039413783Smrg 302139413783Smrg return info->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor); 302239413783Smrg} 302339413783Smrg 302439413783Smrgstatic Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev, 302539413783Smrg ScreenPtr pScreen) 302639413783Smrg{ 302739413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 302839413783Smrg RADEONInfoPtr info = RADEONPTR(scrn); 302939413783Smrg 303039413783Smrg return info->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen); 30318bf5c682Smrg} 3032de2362d3Smrg 303339413783Smrgstatic void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev, 303439413783Smrg ScreenPtr pScreen) 303539413783Smrg{ 303639413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 303739413783Smrg RADEONInfoPtr info = RADEONPTR(scrn); 303839413783Smrg 303939413783Smrg info->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen); 304039413783Smrg} 304139413783Smrg 304239413783SmrgmiPointerSpriteFuncRec drmmode_sprite_funcs = { 304339413783Smrg .RealizeCursor = drmmode_sprite_realize_realize_cursor, 304439413783Smrg .UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor, 304539413783Smrg .SetCursor = drmmode_sprite_set_cursor, 304639413783Smrg .MoveCursor = drmmode_sprite_move_cursor, 304739413783Smrg .DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize, 304839413783Smrg .DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup, 304939413783Smrg}; 305039413783Smrg 305139413783Smrg 3052de2362d3Smrgvoid drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y) 3053de2362d3Smrg{ 3054de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 3055de2362d3Smrg xf86OutputPtr output = config->output[config->compat_output]; 3056de2362d3Smrg xf86CrtcPtr crtc = output->crtc; 3057de2362d3Smrg 3058de2362d3Smrg if (crtc && crtc->enabled) { 3059de2362d3Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 3060de2362d3Smrg x, y); 3061de2362d3Smrg } 3062de2362d3Smrg} 3063de2362d3Smrg 306418781e08SmrgBool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, 306518781e08Smrg Bool set_hw) 3066de2362d3Smrg{ 3067de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 30688bf5c682Smrg unsigned num_desired = 0, num_on = 0; 3069de2362d3Smrg int c; 3070de2362d3Smrg 30718bf5c682Smrg /* First, disable all unused CRTCs */ 30728bf5c682Smrg if (set_hw) { 30738bf5c682Smrg for (c = 0; c < config->num_crtc; c++) { 30748bf5c682Smrg xf86CrtcPtr crtc = config->crtc[c]; 30758bf5c682Smrg 30768bf5c682Smrg /* Skip disabled CRTCs */ 30778bf5c682Smrg if (crtc->enabled) 30788bf5c682Smrg continue; 30798bf5c682Smrg 308039413783Smrg drmmode_crtc_dpms(crtc, DPMSModeOff); 30818bf5c682Smrg } 30828bf5c682Smrg } 30838bf5c682Smrg 30848bf5c682Smrg /* Then, try setting the chosen mode on each CRTC */ 3085de2362d3Smrg for (c = 0; c < config->num_crtc; c++) { 3086de2362d3Smrg xf86CrtcPtr crtc = config->crtc[c]; 3087de2362d3Smrg xf86OutputPtr output = NULL; 3088de2362d3Smrg int o; 3089de2362d3Smrg 30908bf5c682Smrg if (!crtc->enabled) 3091de2362d3Smrg continue; 3092de2362d3Smrg 3093de2362d3Smrg if (config->output[config->compat_output]->crtc == crtc) 3094de2362d3Smrg output = config->output[config->compat_output]; 3095de2362d3Smrg else 3096de2362d3Smrg { 3097de2362d3Smrg for (o = 0; o < config->num_output; o++) 3098de2362d3Smrg if (config->output[o]->crtc == crtc) 3099de2362d3Smrg { 3100de2362d3Smrg output = config->output[o]; 3101de2362d3Smrg break; 3102de2362d3Smrg } 3103de2362d3Smrg } 3104de2362d3Smrg /* paranoia */ 3105de2362d3Smrg if (!output) 3106de2362d3Smrg continue; 3107de2362d3Smrg 31088bf5c682Smrg num_desired++; 31098bf5c682Smrg 3110de2362d3Smrg /* Mark that we'll need to re-set the mode for sure */ 3111de2362d3Smrg memset(&crtc->mode, 0, sizeof(crtc->mode)); 3112de2362d3Smrg if (!crtc->desiredMode.CrtcHDisplay) 3113de2362d3Smrg { 3114de2362d3Smrg DisplayModePtr mode = xf86OutputFindClosestMode (output, pScrn->currentMode); 3115de2362d3Smrg 31168bf5c682Smrg if (!mode) { 31178bf5c682Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 31188bf5c682Smrg "Failed to find mode for CRTC %d\n", c); 31198bf5c682Smrg continue; 31208bf5c682Smrg } 3121de2362d3Smrg crtc->desiredMode = *mode; 3122de2362d3Smrg crtc->desiredRotation = RR_Rotate_0; 3123de2362d3Smrg crtc->desiredX = 0; 3124de2362d3Smrg crtc->desiredY = 0; 3125de2362d3Smrg } 3126de2362d3Smrg 312718781e08Smrg if (set_hw) { 31288bf5c682Smrg if (crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, 31298bf5c682Smrg crtc->desiredRotation, 31308bf5c682Smrg crtc->desiredX, 31318bf5c682Smrg crtc->desiredY)) { 31328bf5c682Smrg num_on++; 31338bf5c682Smrg } else { 31348bf5c682Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 31358bf5c682Smrg "Failed to set mode on CRTC %d\n", c); 313639413783Smrg RRCrtcSet(crtc->randr_crtc, NULL, crtc->x, crtc->y, 313739413783Smrg crtc->rotation, 0, NULL); 31388bf5c682Smrg } 313918781e08Smrg } else { 314018781e08Smrg crtc->mode = crtc->desiredMode; 314118781e08Smrg crtc->rotation = crtc->desiredRotation; 314218781e08Smrg crtc->x = crtc->desiredX; 314318781e08Smrg crtc->y = crtc->desiredY; 31448bf5c682Smrg if (drmmode_handle_transform(crtc)) 31458bf5c682Smrg num_on++; 314618781e08Smrg } 3147de2362d3Smrg } 31488bf5c682Smrg 31498bf5c682Smrg if (num_on == 0 && num_desired > 0) { 31508bf5c682Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to enable any CRTC\n"); 31518bf5c682Smrg return FALSE; 31528bf5c682Smrg } 31538bf5c682Smrg 315439413783Smrg /* Validate leases on VT re-entry */ 3155446f62d6Smrg if (dixPrivateKeyRegistered(rrPrivKey)) 3156446f62d6Smrg drmmode_validate_leases(pScrn); 315739413783Smrg 3158de2362d3Smrg return TRUE; 3159de2362d3Smrg} 3160de2362d3Smrg 316118781e08SmrgBool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn) 3162de2362d3Smrg{ 3163de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 316439413783Smrg int i; 3165de2362d3Smrg 316618781e08Smrg if (xf86_config->num_crtc) { 316718781e08Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 316818781e08Smrg "Initializing kms color map\n"); 316918781e08Smrg if (!miCreateDefColormap(pScreen)) 317018781e08Smrg return FALSE; 31718bf5c682Smrg 31728bf5c682Smrg /* All radeons support 10 bit CLUTs. They get bypassed at depth 30. */ 317339413783Smrg if (pScrn->depth != 30) { 317439413783Smrg if (!xf86HandleColormaps(pScreen, 256, 10, NULL, NULL, 317539413783Smrg CMAP_PALETTED_TRUECOLOR 317639413783Smrg | CMAP_RELOAD_ON_MODE_SWITCH)) 317739413783Smrg return FALSE; 317839413783Smrg 317939413783Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 318039413783Smrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 318139413783Smrg 318239413783Smrg drmmode_crtc_gamma_do_set(crtc, crtc->gamma_red, 318339413783Smrg crtc->gamma_green, 318439413783Smrg crtc->gamma_blue, 318539413783Smrg crtc->gamma_size); 318639413783Smrg } 318739413783Smrg } 318818781e08Smrg } 318939413783Smrg 319018781e08Smrg return TRUE; 319118781e08Smrg} 31927314432eSmrg 319318781e08Smrgstatic Bool 319418781e08Smrgdrmmode_find_output(ScrnInfoPtr scrn, int output_id, int *num_dvi, 319518781e08Smrg int *num_hdmi) 319618781e08Smrg{ 319718781e08Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 319818781e08Smrg int i; 31997314432eSmrg 320018781e08Smrg for (i = 0; i < config->num_output; i++) { 320118781e08Smrg xf86OutputPtr output = config->output[i]; 320218781e08Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 320318781e08Smrg 320418781e08Smrg if (drmmode_output->output_id == output_id) { 320518781e08Smrg switch(drmmode_output->mode_output->connector_type) { 320618781e08Smrg case DRM_MODE_CONNECTOR_DVII: 320718781e08Smrg case DRM_MODE_CONNECTOR_DVID: 320818781e08Smrg case DRM_MODE_CONNECTOR_DVIA: 320918781e08Smrg (*num_dvi)++; 321018781e08Smrg break; 321118781e08Smrg case DRM_MODE_CONNECTOR_HDMIA: 321218781e08Smrg case DRM_MODE_CONNECTOR_HDMIB: 321318781e08Smrg (*num_hdmi)++; 321418781e08Smrg break; 321518781e08Smrg } 321618781e08Smrg 321718781e08Smrg return TRUE; 321818781e08Smrg } 321918781e08Smrg } 322018781e08Smrg 322118781e08Smrg return FALSE; 32227314432eSmrg} 32237314432eSmrg 322418781e08Smrgvoid 322518781e08Smrgradeon_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode) 32260d16fef4Smrg{ 322718781e08Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 322818781e08Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 322918781e08Smrg drmModeResPtr mode_res; 323018781e08Smrg int i, j; 323118781e08Smrg Bool found; 323218781e08Smrg Bool changed = FALSE; 323318781e08Smrg int num_dvi = 0, num_hdmi = 0; 323418781e08Smrg 32358bf5c682Smrg /* Try to re-set the mode on all the connectors with a BAD link-state: 32368bf5c682Smrg * This may happen if a link degrades and a new modeset is necessary, using 32378bf5c682Smrg * different link-training parameters. If the kernel found that the current 32388bf5c682Smrg * mode is not achievable anymore, it should have pruned the mode before 32398bf5c682Smrg * sending the hotplug event. Try to re-set the currently-set mode to keep 32408bf5c682Smrg * the display alive, this will fail if the mode has been pruned. 32418bf5c682Smrg * In any case, we will send randr events for the Desktop Environment to 32428bf5c682Smrg * deal with it, if it wants to. 32438bf5c682Smrg */ 32448bf5c682Smrg for (i = 0; i < config->num_output; i++) { 32458bf5c682Smrg xf86OutputPtr output = config->output[i]; 32468bf5c682Smrg xf86CrtcPtr crtc = output->crtc; 32478bf5c682Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 32488bf5c682Smrg 32498bf5c682Smrg drmmode_output_detect(output); 32508bf5c682Smrg 32518bf5c682Smrg if (!crtc || !drmmode_output->mode_output) 32528bf5c682Smrg continue; 32538bf5c682Smrg 32548bf5c682Smrg /* Get an updated view of the properties for the current connector and 32558bf5c682Smrg * look for the link-status property 32568bf5c682Smrg */ 32578bf5c682Smrg for (j = 0; j < drmmode_output->num_props; j++) { 32588bf5c682Smrg drmmode_prop_ptr p = &drmmode_output->props[j]; 32598bf5c682Smrg 32608bf5c682Smrg if (!strcmp(p->mode_prop->name, "link-status")) { 32618bf5c682Smrg if (p->value != DRM_MODE_LINK_STATUS_BAD) 32628bf5c682Smrg break; 32638bf5c682Smrg 32648bf5c682Smrg /* the connector got a link failure, re-set the current mode */ 32658bf5c682Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 32668bf5c682Smrg crtc->x, crtc->y); 32678bf5c682Smrg 32688bf5c682Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 32698bf5c682Smrg "hotplug event: connector %u's link-state is BAD, " 32708bf5c682Smrg "tried resetting the current mode. You may be left" 32718bf5c682Smrg "with a black screen if this fails...\n", 32728bf5c682Smrg drmmode_output->mode_output->connector_id); 32738bf5c682Smrg 32748bf5c682Smrg break; 32758bf5c682Smrg } 32768bf5c682Smrg } 32778bf5c682Smrg } 32788bf5c682Smrg 32798bf5c682Smrg mode_res = drmModeGetResources(pRADEONEnt->fd); 328018781e08Smrg if (!mode_res) 328118781e08Smrg goto out; 328218781e08Smrg 328318781e08Smrgrestart_destroy: 328418781e08Smrg for (i = 0; i < config->num_output; i++) { 328518781e08Smrg xf86OutputPtr output = config->output[i]; 328618781e08Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 328718781e08Smrg found = FALSE; 328818781e08Smrg for (j = 0; j < mode_res->count_connectors; j++) { 328918781e08Smrg if (mode_res->connectors[j] == drmmode_output->output_id) { 329018781e08Smrg found = TRUE; 329118781e08Smrg break; 329218781e08Smrg } 329318781e08Smrg } 329418781e08Smrg if (found) 329518781e08Smrg continue; 329618781e08Smrg 329718781e08Smrg drmModeFreeConnector(drmmode_output->mode_output); 329818781e08Smrg drmmode_output->mode_output = NULL; 329918781e08Smrg drmmode_output->output_id = -1; 330018781e08Smrg 330118781e08Smrg changed = TRUE; 330218781e08Smrg if (drmmode->delete_dp_12_displays) { 330318781e08Smrg RROutputDestroy(output->randr_output); 330418781e08Smrg xf86OutputDestroy(output); 330518781e08Smrg goto restart_destroy; 330618781e08Smrg } 330718781e08Smrg } 330818781e08Smrg 330918781e08Smrg /* find new output ids we don't have outputs for */ 331018781e08Smrg for (i = 0; i < mode_res->count_connectors; i++) { 3311446f62d6Smrg for (j = 0; j < pRADEONEnt->num_scrns; j++) { 3312446f62d6Smrg if (drmmode_find_output(pRADEONEnt->scrn[j], 3313446f62d6Smrg mode_res->connectors[i], 3314446f62d6Smrg &num_dvi, &num_hdmi)) 3315446f62d6Smrg break; 3316446f62d6Smrg } 3317446f62d6Smrg 3318446f62d6Smrg if (j < pRADEONEnt->num_scrns) 331918781e08Smrg continue; 332018781e08Smrg 332118781e08Smrg if (drmmode_output_init(scrn, drmmode, mode_res, i, &num_dvi, 332218781e08Smrg &num_hdmi, 1) != 0) 332318781e08Smrg changed = TRUE; 332418781e08Smrg } 332518781e08Smrg 332639413783Smrg /* Check to see if a lessee has disappeared */ 332739413783Smrg drmmode_validate_leases(scrn); 332839413783Smrg 3329446f62d6Smrg if (changed) { 333018781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0) 333118781e08Smrg RRSetChanged(xf86ScrnToScreen(scrn)); 333218781e08Smrg#else 333318781e08Smrg rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen); 333418781e08Smrg rrScrPriv->changed = TRUE; 33350d16fef4Smrg#endif 333618781e08Smrg RRTellChanged(xf86ScrnToScreen(scrn)); 333718781e08Smrg } 33387821949aSmrg 333918781e08Smrg drmModeFreeResources(mode_res); 334018781e08Smrgout: 334118781e08Smrg RRGetInfo(xf86ScrnToScreen(scrn), TRUE); 334218781e08Smrg} 3343de2362d3Smrg#ifdef HAVE_LIBUDEV 3344de2362d3Smrgstatic void 3345de2362d3Smrgdrmmode_handle_uevents(int fd, void *closure) 3346de2362d3Smrg{ 3347de2362d3Smrg drmmode_ptr drmmode = closure; 3348de2362d3Smrg ScrnInfoPtr scrn = drmmode->scrn; 3349de2362d3Smrg struct udev_device *dev; 335018781e08Smrg Bool received = FALSE; 33513ed65abbSmrg struct timeval tv = { 0, 0 }; 33523ed65abbSmrg fd_set readfd; 33533ed65abbSmrg 33543ed65abbSmrg FD_ZERO(&readfd); 33553ed65abbSmrg FD_SET(fd, &readfd); 33563ed65abbSmrg 33573ed65abbSmrg while (select(fd + 1, &readfd, NULL, NULL, &tv) > 0 && 33583ed65abbSmrg FD_ISSET(fd, &readfd)) { 33593ed65abbSmrg /* select() ensured that this will not block */ 33603ed65abbSmrg dev = udev_monitor_receive_device(drmmode->uevent_monitor); 33613ed65abbSmrg if (dev) { 33623ed65abbSmrg udev_device_unref(dev); 33633ed65abbSmrg received = TRUE; 33643ed65abbSmrg } 336518781e08Smrg } 336618781e08Smrg 336718781e08Smrg if (received) 336818781e08Smrg radeon_mode_hotplug(scrn, drmmode); 3369de2362d3Smrg} 3370de2362d3Smrg#endif 3371de2362d3Smrg 3372de2362d3Smrgvoid drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3373de2362d3Smrg{ 3374de2362d3Smrg#ifdef HAVE_LIBUDEV 3375de2362d3Smrg struct udev *u; 3376de2362d3Smrg struct udev_monitor *mon; 3377de2362d3Smrg 3378de2362d3Smrg u = udev_new(); 3379de2362d3Smrg if (!u) 3380de2362d3Smrg return; 3381de2362d3Smrg mon = udev_monitor_new_from_netlink(u, "udev"); 3382de2362d3Smrg if (!mon) { 3383de2362d3Smrg udev_unref(u); 3384de2362d3Smrg return; 3385de2362d3Smrg } 3386de2362d3Smrg 3387de2362d3Smrg if (udev_monitor_filter_add_match_subsystem_devtype(mon, 3388de2362d3Smrg "drm", 3389de2362d3Smrg "drm_minor") < 0 || 3390de2362d3Smrg udev_monitor_enable_receiving(mon) < 0) { 3391de2362d3Smrg udev_monitor_unref(mon); 3392de2362d3Smrg udev_unref(u); 3393de2362d3Smrg return; 3394de2362d3Smrg } 3395de2362d3Smrg 3396de2362d3Smrg drmmode->uevent_handler = 3397de2362d3Smrg xf86AddGeneralHandler(udev_monitor_get_fd(mon), 3398de2362d3Smrg drmmode_handle_uevents, 3399de2362d3Smrg drmmode); 3400de2362d3Smrg 3401de2362d3Smrg drmmode->uevent_monitor = mon; 3402de2362d3Smrg#endif 3403de2362d3Smrg} 3404de2362d3Smrg 3405de2362d3Smrgvoid drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3406de2362d3Smrg{ 3407de2362d3Smrg#ifdef HAVE_LIBUDEV 3408de2362d3Smrg if (drmmode->uevent_handler) { 3409de2362d3Smrg struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); 3410de2362d3Smrg xf86RemoveGeneralHandler(drmmode->uevent_handler); 3411de2362d3Smrg 3412de2362d3Smrg udev_monitor_unref(drmmode->uevent_monitor); 3413de2362d3Smrg udev_unref(u); 3414de2362d3Smrg } 3415de2362d3Smrg#endif 3416de2362d3Smrg} 3417de2362d3Smrg 341818781e08SmrgBool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, 34198bf5c682Smrg PixmapPtr new_front, uint64_t id, void *data, 34208bf5c682Smrg xf86CrtcPtr ref_crtc, radeon_drm_handler_proc handler, 342118781e08Smrg radeon_drm_abort_proc abort, 34223ed65abbSmrg enum drmmode_flip_sync flip_sync, 34233ed65abbSmrg uint32_t target_msc) 3424de2362d3Smrg{ 34253ed65abbSmrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 3426de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 342718781e08Smrg xf86CrtcPtr crtc = NULL; 3428de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; 3429446f62d6Smrg int crtc_id; 34303ed65abbSmrg uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0; 3431de2362d3Smrg drmmode_flipdata_ptr flipdata; 343239413783Smrg Bool handle_deferred = FALSE; 343318781e08Smrg uintptr_t drm_queue_seq = 0; 343439413783Smrg struct drmmode_fb *fb; 343539413783Smrg int i = 0; 3436de2362d3Smrg 3437446f62d6Smrg flipdata = calloc(1, sizeof(*flipdata) + drmmode_crtc->drmmode->count_crtcs * 343839413783Smrg sizeof(flipdata->fb[0])); 34397821949aSmrg if (!flipdata) { 34407821949aSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 34417821949aSmrg "flip queue: data alloc failed.\n"); 344218781e08Smrg goto error; 34437821949aSmrg } 344418781e08Smrg 344539413783Smrg fb = radeon_pixmap_get_fb(new_front); 344639413783Smrg if (!fb) { 34478bf5c682Smrg ErrorF("Failed to get FB for flip\n"); 344818781e08Smrg goto error; 34498bf5c682Smrg } 345018781e08Smrg 3451de2362d3Smrg /* 3452de2362d3Smrg * Queue flips on all enabled CRTCs 3453de2362d3Smrg * Note that if/when we get per-CRTC buffers, we'll have to update this. 3454de2362d3Smrg * Right now it assumes a single shared fb across all CRTCs, with the 3455de2362d3Smrg * kernel fixing up the offset of each CRTC as necessary. 3456de2362d3Smrg * 3457de2362d3Smrg * Also, flips queued on disabled or incorrectly configured displays 3458de2362d3Smrg * may never complete; this is a configuration error. 3459de2362d3Smrg */ 3460de2362d3Smrg 3461de2362d3Smrg flipdata->event_data = data; 346218781e08Smrg flipdata->handler = handler; 346318781e08Smrg flipdata->abort = abort; 34648bf5c682Smrg flipdata->fe_crtc = ref_crtc; 346518781e08Smrg 3466de2362d3Smrg for (i = 0; i < config->num_crtc; i++) { 346718781e08Smrg crtc = config->crtc[i]; 34688bf5c682Smrg drmmode_crtc = crtc->driver_private; 3469446f62d6Smrg crtc_id = drmmode_get_crtc_id(crtc); 347018781e08Smrg 34718bf5c682Smrg if (!drmmode_crtc_can_flip(crtc) || 34728bf5c682Smrg (drmmode_crtc->tear_free && crtc != ref_crtc)) 3473de2362d3Smrg continue; 3474de2362d3Smrg 3475de2362d3Smrg flipdata->flip_count++; 347618781e08Smrg 347718781e08Smrg drm_queue_seq = radeon_drm_queue_alloc(crtc, client, id, 347818781e08Smrg flipdata, 347918781e08Smrg drmmode_flip_handler, 3480446f62d6Smrg drmmode_flip_abort, 3481446f62d6Smrg TRUE); 348218781e08Smrg if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { 348318781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 348418781e08Smrg "Allocating DRM queue event entry failed.\n"); 348518781e08Smrg goto error; 348618781e08Smrg } 3487de2362d3Smrg 34888bf5c682Smrg if (drmmode_crtc->tear_free) { 34898bf5c682Smrg BoxRec extents = { .x1 = 0, .y1 = 0, 34908bf5c682Smrg .x2 = new_front->drawable.width, 34918bf5c682Smrg .y2 = new_front->drawable.height }; 34928bf5c682Smrg int scanout_id = drmmode_crtc->scanout_id ^ 1; 34938bf5c682Smrg 34948bf5c682Smrg if (flip_sync == FLIP_ASYNC) { 34958bf5c682Smrg if (!drmmode_wait_vblank(crtc, 34968bf5c682Smrg DRM_VBLANK_RELATIVE | 34978bf5c682Smrg DRM_VBLANK_EVENT, 34988bf5c682Smrg 0, drm_queue_seq, 34998bf5c682Smrg NULL, NULL)) 35008bf5c682Smrg goto flip_error; 35018bf5c682Smrg goto next; 35028bf5c682Smrg } 35038bf5c682Smrg 3504446f62d6Smrg drmmode_fb_reference(pRADEONEnt->fd, &flipdata->fb[crtc_id], 350539413783Smrg radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap)); 3506446f62d6Smrg if (!flipdata->fb[crtc_id]) { 35078bf5c682Smrg ErrorF("Failed to get FB for TearFree flip\n"); 35088bf5c682Smrg goto error; 35098bf5c682Smrg } 35108bf5c682Smrg 35118bf5c682Smrg radeon_scanout_do_update(crtc, scanout_id, new_front, 351239413783Smrg extents); 351339413783Smrg radeon_cs_flush_indirect(crtc->scrn); 351439413783Smrg 351539413783Smrg if (drmmode_crtc->scanout_update_pending) { 351639413783Smrg radeon_drm_wait_pending_flip(crtc); 351739413783Smrg handle_deferred = TRUE; 351839413783Smrg radeon_drm_abort_entry(drmmode_crtc->scanout_update_pending); 351939413783Smrg drmmode_crtc->scanout_update_pending = 0; 352039413783Smrg } 352139413783Smrg } else { 3522446f62d6Smrg drmmode_fb_reference(pRADEONEnt->fd, &flipdata->fb[crtc_id], fb); 35238bf5c682Smrg } 35248bf5c682Smrg 35258bf5c682Smrg if (crtc == ref_crtc) { 35263ed65abbSmrg if (drmmode_page_flip_target_absolute(pRADEONEnt, 35273ed65abbSmrg drmmode_crtc, 3528446f62d6Smrg flipdata->fb[crtc_id]->handle, 35293ed65abbSmrg flip_flags, 35303ed65abbSmrg drm_queue_seq, 35313ed65abbSmrg target_msc) != 0) 35323ed65abbSmrg goto flip_error; 35333ed65abbSmrg } else { 35343ed65abbSmrg if (drmmode_page_flip_target_relative(pRADEONEnt, 35353ed65abbSmrg drmmode_crtc, 3536446f62d6Smrg flipdata->fb[crtc_id]->handle, 35373ed65abbSmrg flip_flags, 35383ed65abbSmrg drm_queue_seq, 0) != 0) 35393ed65abbSmrg goto flip_error; 3540de2362d3Smrg } 35413ed65abbSmrg 35428bf5c682Smrg if (drmmode_crtc->tear_free) { 35438bf5c682Smrg drmmode_crtc->scanout_id ^= 1; 35448bf5c682Smrg drmmode_crtc->ignore_damage = TRUE; 35458bf5c682Smrg } 35468bf5c682Smrg 354739413783Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->flip_pending, 3548446f62d6Smrg flipdata->fb[crtc_id]); 3549446f62d6Smrg 3550446f62d6Smrg next: 355118781e08Smrg drm_queue_seq = 0; 3552de2362d3Smrg } 3553de2362d3Smrg 355439413783Smrg if (handle_deferred) 355539413783Smrg radeon_drm_queue_handle_deferred(ref_crtc); 355618781e08Smrg if (flipdata->flip_count > 0) 355718781e08Smrg return TRUE; 35580d16fef4Smrg 35593ed65abbSmrgflip_error: 35603ed65abbSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n", 35613ed65abbSmrg strerror(errno)); 35623ed65abbSmrg 356318781e08Smrgerror: 356418781e08Smrg if (drm_queue_seq) 356518781e08Smrg radeon_drm_abort_entry(drm_queue_seq); 356618781e08Smrg else if (crtc) 356718781e08Smrg drmmode_flip_abort(crtc, flipdata); 35683ed65abbSmrg else { 35693ed65abbSmrg abort(NULL, data); 357018781e08Smrg free(flipdata); 35713ed65abbSmrg } 3572de2362d3Smrg 3573de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", 3574de2362d3Smrg strerror(errno)); 357539413783Smrg if (handle_deferred) 357639413783Smrg radeon_drm_queue_handle_deferred(ref_crtc); 3577de2362d3Smrg return FALSE; 3578de2362d3Smrg} 3579