drmmode_display.c revision d1d00eb7
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; 873d1d00eb7Sjmcneill uint32_t handle; 874de2362d3Smrg int i; 8758bf5c682Smrg struct drmmode_fb *fb = NULL; 8768bf5c682Smrg 8778bf5c682Smrg /* The root window contents may be undefined before the WindowExposures 8788bf5c682Smrg * hook is called for it, so bail if we get here before that 8798bf5c682Smrg */ 8808bf5c682Smrg if (pScreen->WindowExposures == RADEONWindowExposures_oneshot) 8818bf5c682Smrg return FALSE; 882de2362d3Smrg 883de2362d3Smrg saved_mode = crtc->mode; 884de2362d3Smrg saved_x = crtc->x; 885de2362d3Smrg saved_y = crtc->y; 886de2362d3Smrg saved_rotation = crtc->rotation; 887de2362d3Smrg 888de2362d3Smrg if (mode) { 889de2362d3Smrg crtc->mode = *mode; 890de2362d3Smrg crtc->x = x; 891de2362d3Smrg crtc->y = y; 892de2362d3Smrg crtc->rotation = rotation; 893de2362d3Smrg 89418781e08Smrg if (!drmmode_handle_transform(crtc)) 895de2362d3Smrg goto done; 89618781e08Smrg 8973ed65abbSmrg drmmode_crtc_update_tear_free(crtc); 8983ed65abbSmrg if (drmmode_crtc->tear_free) 8993ed65abbSmrg scanout_id = drmmode_crtc->scanout_id; 90039413783Smrg else 90139413783Smrg drmmode_crtc->scanout_id = 0; 902de2362d3Smrg 9038bf5c682Smrg if (drmmode_crtc->prime_scanout_pixmap) { 9043ed65abbSmrg drmmode_crtc_prime_scanout_update(crtc, mode, scanout_id, 9058bf5c682Smrg &fb, &x, &y); 9068bf5c682Smrg } else if (drmmode_crtc->rotate.pixmap) { 9078bf5c682Smrg fb = radeon_pixmap_get_fb(drmmode_crtc->rotate.pixmap); 90818781e08Smrg x = y = 0; 90918781e08Smrg 9108bf5c682Smrg } else if (!pScreen->isGPU && 9113ed65abbSmrg (drmmode_crtc->tear_free || 91218781e08Smrg crtc->driverIsPerformingTransform || 91318781e08Smrg info->shadow_primary)) { 9143ed65abbSmrg drmmode_crtc_scanout_update(crtc, mode, scanout_id, 9158bf5c682Smrg &fb, &x, &y); 916de2362d3Smrg } 91718781e08Smrg 9188bf5c682Smrg if (!fb) 9198bf5c682Smrg fb = radeon_pixmap_get_fb(pScreen->GetWindowPixmap(pScreen->root)); 9208bf5c682Smrg if (!fb) { 921d1d00eb7Sjmcneill if (info->front_buffer->flags & RADEON_BO_FLAGS_GBM) { 922d1d00eb7Sjmcneill handle = gbm_bo_get_handle(info->front_buffer->bo.gbm).u32; 923d1d00eb7Sjmcneill } else { 924d1d00eb7Sjmcneill handle = info->front_buffer->bo.radeon->handle; 925d1d00eb7Sjmcneill } 9268bf5c682Smrg fb = radeon_fb_create(pScrn, pRADEONEnt->fd, 9278bf5c682Smrg pScrn->virtualX, pScrn->virtualY, 9288bf5c682Smrg pScrn->displayWidth * info->pixel_bytes, 929d1d00eb7Sjmcneill handle); 9308bf5c682Smrg /* Prevent refcnt of ad-hoc FBs from reaching 2 */ 9318bf5c682Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, NULL); 9328bf5c682Smrg drmmode_crtc->fb = fb; 9338bf5c682Smrg } 9348bf5c682Smrg if (!fb) { 9358bf5c682Smrg ErrorF("failed to add FB for modeset\n"); 9368bf5c682Smrg goto done; 93718781e08Smrg } 93818781e08Smrg 93939413783Smrg radeon_drm_wait_pending_flip(crtc); 940446f62d6Smrg handle_deferred = TRUE; 9418bf5c682Smrg 9428bf5c682Smrg if (!drmmode_set_mode(crtc, fb, mode, x, y)) 94318781e08Smrg goto done; 9448bf5c682Smrg 9458bf5c682Smrg ret = TRUE; 946de2362d3Smrg 94718781e08Smrg if (pScreen) 94818781e08Smrg xf86CrtcSetScreenSubpixelOrder(pScreen); 94918781e08Smrg 95018781e08Smrg drmmode_crtc->need_modeset = FALSE; 95118781e08Smrg 952de2362d3Smrg /* go through all the outputs and force DPMS them back on? */ 953de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 954de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 955de2362d3Smrg 956de2362d3Smrg if (output->crtc != crtc) 957de2362d3Smrg continue; 958de2362d3Smrg 959de2362d3Smrg output->funcs->dpms(output, DPMSModeOn); 960de2362d3Smrg } 961de2362d3Smrg } 962de2362d3Smrg 96318781e08Smrg /* Compute index of this CRTC into xf86_config->crtc */ 96418781e08Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 96518781e08Smrg if (xf86_config->crtc[i] != crtc) 96618781e08Smrg continue; 96718781e08Smrg 96818781e08Smrg if (!crtc->enabled || drmmode_can_use_hw_cursor(crtc)) 96918781e08Smrg info->hwcursor_disabled &= ~(1 << i); 97018781e08Smrg else 97118781e08Smrg info->hwcursor_disabled |= 1 << i; 97218781e08Smrg 97318781e08Smrg break; 97418781e08Smrg } 97518781e08Smrg 97618781e08Smrg#ifndef HAVE_XF86_CURSOR_RESET_CURSOR 97718781e08Smrg if (!info->hwcursor_disabled) 97818781e08Smrg xf86_reload_cursors(pScreen); 97918781e08Smrg#endif 980de2362d3Smrg 981de2362d3Smrgdone: 982de2362d3Smrg if (!ret) { 983de2362d3Smrg crtc->x = saved_x; 984de2362d3Smrg crtc->y = saved_y; 985de2362d3Smrg crtc->rotation = saved_rotation; 986de2362d3Smrg crtc->mode = saved_mode; 98718781e08Smrg } else { 9887821949aSmrg crtc->active = TRUE; 98918781e08Smrg 9908bf5c682Smrg if (drmmode_crtc->scanout[scanout_id].pixmap && 9918bf5c682Smrg fb != radeon_pixmap_get_fb(drmmode_crtc-> 99239413783Smrg scanout[scanout_id].pixmap)) { 993446f62d6Smrg drmmode_crtc_scanout_free(crtc); 99439413783Smrg } else if (!drmmode_crtc->tear_free) { 9953ed65abbSmrg drmmode_crtc_scanout_destroy(drmmode, 9963ed65abbSmrg &drmmode_crtc->scanout[1]); 9973ed65abbSmrg } 99818781e08Smrg } 99918781e08Smrg 1000446f62d6Smrg if (handle_deferred) 1001446f62d6Smrg radeon_drm_queue_handle_deferred(crtc); 1002446f62d6Smrg 1003de2362d3Smrg return ret; 1004de2362d3Smrg} 1005de2362d3Smrg 1006de2362d3Smrgstatic void 1007de2362d3Smrgdrmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg) 1008de2362d3Smrg{ 1009de2362d3Smrg 1010de2362d3Smrg} 1011de2362d3Smrg 1012de2362d3Smrgstatic void 1013de2362d3Smrgdrmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y) 1014de2362d3Smrg{ 1015de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 10168bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 1017de2362d3Smrg 10188bf5c682Smrg#if XF86_CRTC_VERSION < 7 101918781e08Smrg if (crtc->driverIsPerformingTransform) { 102018781e08Smrg x += crtc->x; 102118781e08Smrg y += crtc->y; 102218781e08Smrg xf86CrtcTransformCursorPos(crtc, &x, &y); 102318781e08Smrg } 102418781e08Smrg#endif 102518781e08Smrg 1026446f62d6Smrg drmmode_crtc->cursor_x = x; 1027446f62d6Smrg drmmode_crtc->cursor_y = y; 1028446f62d6Smrg 10298bf5c682Smrg drmModeMoveCursor(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); 1030de2362d3Smrg} 1031de2362d3Smrg 10328bf5c682Smrg#if XF86_CRTC_VERSION < 7 103318781e08Smrg 103418781e08Smrgstatic int 103518781e08Smrgdrmmode_cursor_src_offset(Rotation rotation, int width, int height, 103618781e08Smrg int x_dst, int y_dst) 103718781e08Smrg{ 103818781e08Smrg int t; 103918781e08Smrg 104018781e08Smrg switch (rotation & 0xf) { 104118781e08Smrg case RR_Rotate_90: 104218781e08Smrg t = x_dst; 104318781e08Smrg x_dst = height - y_dst - 1; 104418781e08Smrg y_dst = t; 104518781e08Smrg break; 104618781e08Smrg case RR_Rotate_180: 104718781e08Smrg x_dst = width - x_dst - 1; 104818781e08Smrg y_dst = height - y_dst - 1; 104918781e08Smrg break; 105018781e08Smrg case RR_Rotate_270: 105118781e08Smrg t = x_dst; 105218781e08Smrg x_dst = y_dst; 105318781e08Smrg y_dst = width - t - 1; 105418781e08Smrg break; 105518781e08Smrg } 105618781e08Smrg 105718781e08Smrg if (rotation & RR_Reflect_X) 105818781e08Smrg x_dst = width - x_dst - 1; 105918781e08Smrg if (rotation & RR_Reflect_Y) 106018781e08Smrg y_dst = height - y_dst - 1; 106118781e08Smrg 106218781e08Smrg return y_dst * height + x_dst; 106318781e08Smrg} 106418781e08Smrg 106518781e08Smrg#endif 106618781e08Smrg 1067446f62d6Smrgstatic Bool 1068446f62d6Smrgdrmmode_cursor_pixel(xf86CrtcPtr crtc, uint32_t *argb, Bool *premultiplied, 1069446f62d6Smrg Bool *apply_gamma) 10708bf5c682Smrg{ 1071446f62d6Smrg uint32_t alpha = *argb >> 24; 10728bf5c682Smrg uint32_t rgb[3]; 10738bf5c682Smrg int i; 10748bf5c682Smrg 1075446f62d6Smrg if (premultiplied) { 1076446f62d6Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1, 18, 4, 0, 0) 1077446f62d6Smrg if (alpha == 0 && (*argb & 0xffffff) != 0) { 1078446f62d6Smrg /* Doesn't look like premultiplied alpha */ 1079446f62d6Smrg *premultiplied = FALSE; 1080446f62d6Smrg return FALSE; 1081446f62d6Smrg } 1082446f62d6Smrg#endif 10838bf5c682Smrg 1084446f62d6Smrg if (!(*apply_gamma)) 1085446f62d6Smrg return TRUE; 1086446f62d6Smrg 1087446f62d6Smrg if (*argb > (alpha | alpha << 8 | alpha << 16 | alpha << 24)) { 1088446f62d6Smrg /* Un-premultiplied R/G/B would overflow gamma LUT, 1089446f62d6Smrg * don't apply gamma correction 1090446f62d6Smrg */ 1091446f62d6Smrg *apply_gamma = FALSE; 1092446f62d6Smrg return FALSE; 1093446f62d6Smrg } 1094446f62d6Smrg } 1095446f62d6Smrg 1096446f62d6Smrg if (!alpha) { 1097446f62d6Smrg *argb = 0; 1098446f62d6Smrg return TRUE; 1099446f62d6Smrg } 11008bf5c682Smrg 1101446f62d6Smrg /* Extract RGB */ 11028bf5c682Smrg for (i = 0; i < 3; i++) 1103446f62d6Smrg rgb[i] = (*argb >> (i * 8)) & 0xff; 1104446f62d6Smrg 1105446f62d6Smrg if (premultiplied) { 1106446f62d6Smrg /* Un-premultiply alpha */ 1107446f62d6Smrg for (i = 0; i < 3; i++) 1108446f62d6Smrg rgb[i] = rgb[i] * 0xff / alpha; 1109446f62d6Smrg } 11108bf5c682Smrg 1111446f62d6Smrg if (*apply_gamma) { 1112446f62d6Smrg rgb[0] = crtc->gamma_blue[rgb[0]] >> 8; 1113446f62d6Smrg rgb[1] = crtc->gamma_green[rgb[1]] >> 8; 1114446f62d6Smrg rgb[2] = crtc->gamma_red[rgb[2]] >> 8; 1115446f62d6Smrg } 11168bf5c682Smrg 1117446f62d6Smrg /* Premultiply alpha */ 1118446f62d6Smrg for (i = 0; i < 3; i++) 1119446f62d6Smrg rgb[i] = rgb[i] * alpha / 0xff; 1120446f62d6Smrg 1121446f62d6Smrg *argb = alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0]; 1122446f62d6Smrg return TRUE; 11238bf5c682Smrg} 11248bf5c682Smrg 1125de2362d3Smrgstatic void 1126de2362d3Smrgdrmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image) 1127de2362d3Smrg{ 112818781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 112918781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1130de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1131446f62d6Smrg unsigned id = drmmode_crtc->cursor_id; 1132446f62d6Smrg Bool premultiplied = TRUE; 1133446f62d6Smrg Bool apply_gamma = TRUE; 1134446f62d6Smrg uint32_t argb; 1135de2362d3Smrg uint32_t *ptr; 1136de2362d3Smrg 1137446f62d6Smrg if (drmmode_crtc->cursor && 1138446f62d6Smrg XF86_CRTC_CONFIG_PTR(pScrn)->cursor != drmmode_crtc->cursor) 1139446f62d6Smrg id ^= 1; 1140446f62d6Smrg 1141de2362d3Smrg /* cursor should be mapped already */ 1142446f62d6Smrg ptr = (uint32_t *)(drmmode_crtc->cursor_bo[id]->ptr); 1143446f62d6Smrg 1144446f62d6Smrg if (crtc->scrn->depth != 24 && crtc->scrn->depth != 32) 1145446f62d6Smrg apply_gamma = FALSE; 1146de2362d3Smrg 11478bf5c682Smrg#if XF86_CRTC_VERSION < 7 114818781e08Smrg if (crtc->driverIsPerformingTransform) { 114918781e08Smrg uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h; 115018781e08Smrg int dstx, dsty; 115118781e08Smrg int srcoffset; 115218781e08Smrg 1153446f62d6Smrgretry_transform: 115418781e08Smrg for (dsty = 0; dsty < cursor_h; dsty++) { 115518781e08Smrg for (dstx = 0; dstx < cursor_w; dstx++) { 115618781e08Smrg srcoffset = drmmode_cursor_src_offset(crtc->rotation, 115718781e08Smrg cursor_w, 115818781e08Smrg cursor_h, 115918781e08Smrg dstx, dsty); 1160446f62d6Smrg argb = image[srcoffset]; 1161446f62d6Smrg if (!drmmode_cursor_pixel(crtc, &argb, &premultiplied, 1162446f62d6Smrg &apply_gamma)) 1163446f62d6Smrg goto retry_transform; 116418781e08Smrg 1165446f62d6Smrg ptr[dsty * info->cursor_w + dstx] = cpu_to_le32(argb); 116618781e08Smrg } 116718781e08Smrg } 116818781e08Smrg } else 116918781e08Smrg#endif 117018781e08Smrg { 117118781e08Smrg uint32_t cursor_size = info->cursor_w * info->cursor_h; 117218781e08Smrg int i; 117318781e08Smrg 1174446f62d6Smrgretry: 1175446f62d6Smrg for (i = 0; i < cursor_size; i++) { 1176446f62d6Smrg argb = image[i]; 1177446f62d6Smrg if (!drmmode_cursor_pixel(crtc, &argb, &premultiplied, 1178446f62d6Smrg &apply_gamma)) 1179446f62d6Smrg goto retry; 1180446f62d6Smrg 1181446f62d6Smrg ptr[i] = cpu_to_le32(argb); 1182446f62d6Smrg } 1183446f62d6Smrg } 1184446f62d6Smrg 1185446f62d6Smrg if (id != drmmode_crtc->cursor_id) { 1186446f62d6Smrg drmmode_crtc->cursor_id = id; 1187446f62d6Smrg crtc->funcs->show_cursor(crtc); 118818781e08Smrg } 1189de2362d3Smrg} 1190de2362d3Smrg 119118781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 119218781e08Smrg 119318781e08Smrgstatic Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image) 119418781e08Smrg{ 119518781e08Smrg if (!drmmode_can_use_hw_cursor(crtc)) 119618781e08Smrg return FALSE; 119718781e08Smrg 119818781e08Smrg drmmode_load_cursor_argb(crtc, image); 119918781e08Smrg return TRUE; 120018781e08Smrg} 120118781e08Smrg 120218781e08Smrg#endif 1203de2362d3Smrg 1204de2362d3Smrgstatic void 1205de2362d3Smrgdrmmode_hide_cursor (xf86CrtcPtr crtc) 1206de2362d3Smrg{ 120718781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 120818781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1209de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 12108bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 1211de2362d3Smrg 12128bf5c682Smrg drmModeSetCursor(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 121318781e08Smrg info->cursor_w, info->cursor_h); 1214446f62d6Smrg drmmode_crtc->cursor = NULL; 1215de2362d3Smrg} 1216de2362d3Smrg 1217de2362d3Smrgstatic void 1218de2362d3Smrgdrmmode_show_cursor (xf86CrtcPtr crtc) 1219de2362d3Smrg{ 122018781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 122118781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1222de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 12238bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 1224446f62d6Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1225446f62d6Smrg CursorPtr cursor = xf86_config->cursor; 1226446f62d6Smrg int xhot = cursor->bits->xhot; 1227446f62d6Smrg int yhot = cursor->bits->yhot; 122818781e08Smrg static Bool use_set_cursor2 = TRUE; 1229446f62d6Smrg struct drm_mode_cursor2 arg; 1230446f62d6Smrg 1231446f62d6Smrg drmmode_crtc->cursor = xf86_config->cursor; 1232446f62d6Smrg 1233446f62d6Smrg memset(&arg, 0, sizeof(arg)); 1234446f62d6Smrg 1235446f62d6Smrg arg.handle = drmmode_crtc->cursor_bo[drmmode_crtc->cursor_id]->handle; 1236446f62d6Smrg arg.flags = DRM_MODE_CURSOR_BO; 1237446f62d6Smrg arg.crtc_id = drmmode_crtc->mode_crtc->crtc_id; 1238446f62d6Smrg arg.width = info->cursor_w; 1239446f62d6Smrg arg.height = info->cursor_h; 1240446f62d6Smrg 1241446f62d6Smrg if (crtc->rotation != RR_Rotate_0 && 1242446f62d6Smrg crtc->rotation != (RR_Rotate_180 | RR_Reflect_X | 1243446f62d6Smrg RR_Reflect_Y)) { 1244446f62d6Smrg int t; 1245446f62d6Smrg 1246446f62d6Smrg /* Reflect & rotate hotspot position */ 1247446f62d6Smrg if (crtc->rotation & RR_Reflect_X) 1248446f62d6Smrg xhot = info->cursor_w - xhot - 1; 1249446f62d6Smrg if (crtc->rotation & RR_Reflect_Y) 1250446f62d6Smrg yhot = info->cursor_h - yhot - 1; 1251446f62d6Smrg 1252446f62d6Smrg switch (crtc->rotation & 0xf) { 1253446f62d6Smrg case RR_Rotate_90: 1254446f62d6Smrg t = xhot; 1255446f62d6Smrg xhot = yhot; 1256446f62d6Smrg yhot = info->cursor_w - t - 1; 1257446f62d6Smrg break; 1258446f62d6Smrg case RR_Rotate_180: 1259446f62d6Smrg xhot = info->cursor_w - xhot - 1; 1260446f62d6Smrg yhot = info->cursor_h - yhot - 1; 1261446f62d6Smrg break; 1262446f62d6Smrg case RR_Rotate_270: 1263446f62d6Smrg t = xhot; 1264446f62d6Smrg xhot = info->cursor_h - yhot - 1; 1265446f62d6Smrg yhot = t; 1266446f62d6Smrg } 1267446f62d6Smrg } 1268446f62d6Smrg 1269446f62d6Smrg if (xhot != drmmode_crtc->cursor_xhot || yhot != drmmode_crtc->cursor_yhot) { 1270446f62d6Smrg arg.flags |= DRM_MODE_CURSOR_MOVE; 1271446f62d6Smrg arg.x = drmmode_crtc->cursor_x += drmmode_crtc->cursor_xhot - xhot; 1272446f62d6Smrg arg.y = drmmode_crtc->cursor_y += drmmode_crtc->cursor_yhot - yhot; 1273446f62d6Smrg drmmode_crtc->cursor_xhot = xhot; 1274446f62d6Smrg drmmode_crtc->cursor_yhot = yhot; 1275446f62d6Smrg } 127618781e08Smrg 127718781e08Smrg if (use_set_cursor2) { 127818781e08Smrg int ret; 127918781e08Smrg 1280446f62d6Smrg arg.hot_x = xhot; 1281446f62d6Smrg arg.hot_y = yhot; 12827314432eSmrg 1283446f62d6Smrg ret = drmIoctl(pRADEONEnt->fd, DRM_IOCTL_MODE_CURSOR2, &arg); 128418781e08Smrg if (ret == -EINVAL) 128518781e08Smrg use_set_cursor2 = FALSE; 128618781e08Smrg else 128718781e08Smrg return; 128818781e08Smrg } 128918781e08Smrg 1290446f62d6Smrg drmIoctl(pRADEONEnt->fd, DRM_IOCTL_MODE_CURSOR, &arg); 1291de2362d3Smrg} 1292de2362d3Smrg 12933ed65abbSmrg/* Xorg expects a non-NULL return value from drmmode_crtc_shadow_allocate, and 12943ed65abbSmrg * passes that back to drmmode_crtc_scanout_create; it doesn't use it for 12953ed65abbSmrg * anything else. 12963ed65abbSmrg */ 1297de2362d3Smrgstatic void * 1298de2362d3Smrgdrmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 1299de2362d3Smrg{ 1300de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 13017821949aSmrg 13023ed65abbSmrg if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 13033ed65abbSmrg height)) 13043ed65abbSmrg return NULL; 13053ed65abbSmrg 13063ed65abbSmrg return (void*)~0UL; 1307de2362d3Smrg} 1308de2362d3Smrg 1309de2362d3Smrgstatic PixmapPtr 1310de2362d3Smrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 1311de2362d3Smrg{ 1312de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1313de2362d3Smrg 13143ed65abbSmrg if (!data) { 13153ed65abbSmrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 13163ed65abbSmrg height); 13173ed65abbSmrg } 13183ed65abbSmrg 13193ed65abbSmrg return drmmode_crtc->rotate.pixmap; 1320de2362d3Smrg} 1321de2362d3Smrg 1322de2362d3Smrgstatic void 13237821949aSmrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) 1324de2362d3Smrg{ 1325de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1326de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 1327de2362d3Smrg 132818781e08Smrg drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate); 13297821949aSmrg} 1330de2362d3Smrg 13317821949aSmrgstatic void 13327821949aSmrgdrmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 13337821949aSmrg uint16_t *blue, int size) 13347821949aSmrg{ 13358bf5c682Smrg ScrnInfoPtr scrn = crtc->scrn; 13368bf5c682Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 13378bf5c682Smrg RADEONInfoPtr info = RADEONPTR(scrn); 13388bf5c682Smrg int i; 13398bf5c682Smrg 13408bf5c682Smrg drmmode_crtc_gamma_do_set(crtc, red, green, blue, size); 13418bf5c682Smrg 13428bf5c682Smrg /* Compute index of this CRTC into xf86_config->crtc */ 13438bf5c682Smrg for (i = 0; xf86_config->crtc[i] != crtc; i++) {} 13448bf5c682Smrg 13458bf5c682Smrg if (info->hwcursor_disabled & (1 << i)) 13468bf5c682Smrg return; 13477314432eSmrg 13488bf5c682Smrg#ifdef HAVE_XF86_CURSOR_RESET_CURSOR 13498bf5c682Smrg xf86CursorResetCursor(scrn->pScreen); 13508bf5c682Smrg#else 13518bf5c682Smrg xf86_reload_cursors(scrn->pScreen); 13528bf5c682Smrg#endif 135318781e08Smrg} 135418781e08Smrg 135518781e08Smrgstatic Bool 135618781e08Smrgdrmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) 135718781e08Smrg{ 135818781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 13593ed65abbSmrg unsigned scanout_id = drmmode_crtc->scanout_id; 136018781e08Smrg ScreenPtr screen = crtc->scrn->pScreen; 136118781e08Smrg PixmapDirtyUpdatePtr dirty; 136218781e08Smrg 136318781e08Smrg xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 13648bf5c682Smrg if (radeon_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) { 13658bf5c682Smrg PixmapStopDirtyTracking(dirty->src, dirty->slave_dst); 13668bf5c682Smrg break; 13678bf5c682Smrg } 136818781e08Smrg } 136918781e08Smrg 1370446f62d6Smrg drmmode_crtc_scanout_free(crtc); 13718bf5c682Smrg drmmode_crtc->prime_scanout_pixmap = NULL; 13728bf5c682Smrg 137318781e08Smrg if (!ppix) 137418781e08Smrg return TRUE; 137518781e08Smrg 137618781e08Smrg if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0], 137718781e08Smrg ppix->drawable.width, 137818781e08Smrg ppix->drawable.height)) 137918781e08Smrg return FALSE; 138018781e08Smrg 13813ed65abbSmrg if (drmmode_crtc->tear_free && 138218781e08Smrg !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 138318781e08Smrg ppix->drawable.width, 138418781e08Smrg ppix->drawable.height)) { 1385446f62d6Smrg drmmode_crtc_scanout_free(crtc); 138618781e08Smrg return FALSE; 138718781e08Smrg } 138818781e08Smrg 13898bf5c682Smrg drmmode_crtc->prime_scanout_pixmap = ppix; 13908bf5c682Smrg 13918bf5c682Smrg#ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC 13928bf5c682Smrg PixmapStartDirtyTracking(&ppix->drawable, 13938bf5c682Smrg drmmode_crtc->scanout[scanout_id].pixmap, 13948bf5c682Smrg 0, 0, 0, 0, RR_Rotate_0); 13958bf5c682Smrg#elif defined(HAS_DIRTYTRACKING_ROTATION) 13963ed65abbSmrg PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 139718781e08Smrg 0, 0, 0, 0, RR_Rotate_0); 139818781e08Smrg#elif defined(HAS_DIRTYTRACKING2) 13993ed65abbSmrg PixmapStartDirtyTracking2(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 140018781e08Smrg 0, 0, 0, 0); 140118781e08Smrg#else 14023ed65abbSmrg PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 0, 0); 140318781e08Smrg#endif 140418781e08Smrg return TRUE; 1405de2362d3Smrg} 1406de2362d3Smrg 140718781e08Smrgstatic xf86CrtcFuncsRec drmmode_crtc_funcs = { 1408de2362d3Smrg .dpms = drmmode_crtc_dpms, 1409de2362d3Smrg .set_mode_major = drmmode_set_mode_major, 1410de2362d3Smrg .set_cursor_colors = drmmode_set_cursor_colors, 1411de2362d3Smrg .set_cursor_position = drmmode_set_cursor_position, 1412de2362d3Smrg .show_cursor = drmmode_show_cursor, 1413de2362d3Smrg .hide_cursor = drmmode_hide_cursor, 1414de2362d3Smrg .load_cursor_argb = drmmode_load_cursor_argb, 141518781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 141618781e08Smrg .load_cursor_argb_check = drmmode_load_cursor_argb_check, 141718781e08Smrg#endif 1418de2362d3Smrg 1419de2362d3Smrg .gamma_set = drmmode_crtc_gamma_set, 1420de2362d3Smrg .shadow_create = drmmode_crtc_shadow_create, 1421de2362d3Smrg .shadow_allocate = drmmode_crtc_shadow_allocate, 1422de2362d3Smrg .shadow_destroy = drmmode_crtc_shadow_destroy, 1423de2362d3Smrg .destroy = NULL, /* XXX */ 142418781e08Smrg .set_scanout_pixmap = drmmode_set_scanout_pixmap, 1425de2362d3Smrg}; 1426de2362d3Smrg 1427de2362d3Smrgint drmmode_get_crtc_id(xf86CrtcPtr crtc) 1428de2362d3Smrg{ 1429de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1430de2362d3Smrg return drmmode_crtc->hw_id; 1431de2362d3Smrg} 1432de2362d3Smrg 1433de2362d3Smrgvoid drmmode_crtc_hw_id(xf86CrtcPtr crtc) 1434de2362d3Smrg{ 1435de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 14368bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 1437de2362d3Smrg struct drm_radeon_info ginfo; 1438de2362d3Smrg int r; 1439de2362d3Smrg uint32_t tmp; 1440de2362d3Smrg 1441de2362d3Smrg memset(&ginfo, 0, sizeof(ginfo)); 1442de2362d3Smrg ginfo.request = 0x4; 1443de2362d3Smrg tmp = drmmode_crtc->mode_crtc->crtc_id; 1444de2362d3Smrg ginfo.value = (uintptr_t)&tmp; 14458bf5c682Smrg r = drmCommandWriteRead(pRADEONEnt->fd, DRM_RADEON_INFO, &ginfo, sizeof(ginfo)); 1446de2362d3Smrg if (r) { 1447de2362d3Smrg drmmode_crtc->hw_id = -1; 1448de2362d3Smrg return; 1449de2362d3Smrg } 1450de2362d3Smrg drmmode_crtc->hw_id = tmp; 1451de2362d3Smrg} 1452de2362d3Smrg 145318781e08Smrgstatic unsigned int 145418781e08Smrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num) 1455de2362d3Smrg{ 1456de2362d3Smrg xf86CrtcPtr crtc; 1457de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc; 145818781e08Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 14598bf5c682Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1460de2362d3Smrg 14618bf5c682Smrg crtc = xf86CrtcCreate(pScrn, &info->drmmode_crtc_funcs); 146239413783Smrg if (!crtc) 146318781e08Smrg return 0; 1464de2362d3Smrg 1465de2362d3Smrg drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); 14668bf5c682Smrg drmmode_crtc->mode_crtc = drmModeGetCrtc(pRADEONEnt->fd, mode_res->crtcs[num]); 1467de2362d3Smrg drmmode_crtc->drmmode = drmmode; 146818781e08Smrg drmmode_crtc->dpms_mode = DPMSModeOff; 1469de2362d3Smrg crtc->driver_private = drmmode_crtc; 1470de2362d3Smrg drmmode_crtc_hw_id(crtc); 1471de2362d3Smrg 147218781e08Smrg /* Mark num'th crtc as in use on this device. */ 147318781e08Smrg pRADEONEnt->assigned_crtcs |= (1 << num); 147418781e08Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 147518781e08Smrg "Allocated crtc nr. %d to this screen.\n", num); 147618781e08Smrg 147718781e08Smrg return 1; 1478de2362d3Smrg} 1479de2362d3Smrg 14808bf5c682Smrg/* 14818bf5c682Smrg * Update all of the property values for an output 14828bf5c682Smrg */ 14838bf5c682Smrgstatic void 14848bf5c682Smrgdrmmode_output_update_properties(xf86OutputPtr output) 14858bf5c682Smrg{ 14868bf5c682Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 14878bf5c682Smrg int i, j, k; 14888bf5c682Smrg int err; 14898bf5c682Smrg drmModeConnectorPtr koutput; 14908bf5c682Smrg 14918bf5c682Smrg /* Use the most recently fetched values from the kernel */ 14928bf5c682Smrg koutput = drmmode_output->mode_output; 14938bf5c682Smrg 14948bf5c682Smrg if (!koutput) 14958bf5c682Smrg return; 14968bf5c682Smrg 14978bf5c682Smrg for (i = 0; i < drmmode_output->num_props; i++) { 14988bf5c682Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 14998bf5c682Smrg 15008bf5c682Smrg for (j = 0; j < koutput->count_props; j++) { 15018bf5c682Smrg if (koutput->props[j] != p->mode_prop->prop_id) 15028bf5c682Smrg continue; 15038bf5c682Smrg 15048bf5c682Smrg /* Check to see if the property value has changed */ 15058bf5c682Smrg if (koutput->prop_values[j] == p->value) 15068bf5c682Smrg break; 15078bf5c682Smrg 15088bf5c682Smrg p->value = koutput->prop_values[j]; 15098bf5c682Smrg 15108bf5c682Smrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 15118bf5c682Smrg INT32 value = p->value; 15128bf5c682Smrg 15138bf5c682Smrg err = RRChangeOutputProperty(output->randr_output, 15148bf5c682Smrg p->atoms[0], XA_INTEGER, 15158bf5c682Smrg 32, PropModeReplace, 1, 15168bf5c682Smrg &value, FALSE, TRUE); 15178bf5c682Smrg if (err != 0) { 15188bf5c682Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 15198bf5c682Smrg "RRChangeOutputProperty error, %d\n", 15208bf5c682Smrg err); 15218bf5c682Smrg } 15228bf5c682Smrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 15238bf5c682Smrg for (k = 0; k < p->mode_prop->count_enums; k++) { 15248bf5c682Smrg if (p->mode_prop->enums[k].value == p->value) 15258bf5c682Smrg break; 15268bf5c682Smrg } 15278bf5c682Smrg if (k < p->mode_prop->count_enums) { 15288bf5c682Smrg err = RRChangeOutputProperty(output->randr_output, 15298bf5c682Smrg p->atoms[0], XA_ATOM, 15308bf5c682Smrg 32, PropModeReplace, 1, 15318bf5c682Smrg &p->atoms[k + 1], FALSE, 15328bf5c682Smrg TRUE); 15338bf5c682Smrg if (err != 0) { 15348bf5c682Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 15358bf5c682Smrg "RRChangeOutputProperty error, %d\n", 15368bf5c682Smrg err); 15378bf5c682Smrg } 15388bf5c682Smrg } 15398bf5c682Smrg } 15408bf5c682Smrg 15418bf5c682Smrg break; 15428bf5c682Smrg } 15438bf5c682Smrg } 15448bf5c682Smrg} 15458bf5c682Smrg 1546de2362d3Smrgstatic xf86OutputStatus 1547de2362d3Smrgdrmmode_output_detect(xf86OutputPtr output) 1548de2362d3Smrg{ 1549de2362d3Smrg /* go to the hw and retrieve a new output struct */ 1550de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 15518bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 1552de2362d3Smrg xf86OutputStatus status; 1553de2362d3Smrg drmModeFreeConnector(drmmode_output->mode_output); 1554de2362d3Smrg 15558bf5c682Smrg drmmode_output->mode_output = 15568bf5c682Smrg drmModeGetConnector(pRADEONEnt->fd, drmmode_output->output_id); 15578bf5c682Smrg if (!drmmode_output->mode_output) { 15588bf5c682Smrg drmmode_output->output_id = -1; 155918781e08Smrg return XF86OutputStatusDisconnected; 15608bf5c682Smrg } 15618bf5c682Smrg 15628bf5c682Smrg drmmode_output_update_properties(output); 1563de2362d3Smrg 1564de2362d3Smrg switch (drmmode_output->mode_output->connection) { 1565de2362d3Smrg case DRM_MODE_CONNECTED: 1566de2362d3Smrg status = XF86OutputStatusConnected; 1567de2362d3Smrg break; 1568de2362d3Smrg case DRM_MODE_DISCONNECTED: 1569de2362d3Smrg status = XF86OutputStatusDisconnected; 1570de2362d3Smrg break; 1571de2362d3Smrg default: 1572de2362d3Smrg case DRM_MODE_UNKNOWNCONNECTION: 1573de2362d3Smrg status = XF86OutputStatusUnknown; 1574de2362d3Smrg break; 1575de2362d3Smrg } 1576de2362d3Smrg return status; 1577de2362d3Smrg} 1578de2362d3Smrg 1579de2362d3Smrgstatic Bool 1580de2362d3Smrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) 1581de2362d3Smrg{ 1582de2362d3Smrg return MODE_OK; 1583de2362d3Smrg} 1584de2362d3Smrg 1585446f62d6Smrgstatic void 1586446f62d6Smrgdrmmode_output_attach_tile(xf86OutputPtr output) 1587446f62d6Smrg{ 1588446f62d6Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1, 17, 99, 901, 0) 1589446f62d6Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1590446f62d6Smrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 1591446f62d6Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 1592446f62d6Smrg struct xf86CrtcTileInfo tile_info, *set = NULL; 1593446f62d6Smrg int i; 1594446f62d6Smrg 1595446f62d6Smrg if (!koutput) { 1596446f62d6Smrg xf86OutputSetTile(output, NULL); 1597446f62d6Smrg return; 1598446f62d6Smrg } 1599446f62d6Smrg 1600446f62d6Smrg /* look for a TILE property */ 1601446f62d6Smrg for (i = 0; i < koutput->count_props; i++) { 1602446f62d6Smrg drmModePropertyPtr props; 1603446f62d6Smrg props = drmModeGetProperty(pRADEONEnt->fd, koutput->props[i]); 1604446f62d6Smrg if (!props) 1605446f62d6Smrg continue; 1606446f62d6Smrg 1607446f62d6Smrg if (!(props->flags & DRM_MODE_PROP_BLOB)) { 1608446f62d6Smrg drmModeFreeProperty(props); 1609446f62d6Smrg continue; 1610446f62d6Smrg } 1611446f62d6Smrg 1612446f62d6Smrg if (!strcmp(props->name, "TILE")) { 1613446f62d6Smrg drmModeFreePropertyBlob(drmmode_output->tile_blob); 1614446f62d6Smrg drmmode_output->tile_blob = 1615446f62d6Smrg drmModeGetPropertyBlob(pRADEONEnt->fd, 1616446f62d6Smrg koutput->prop_values[i]); 1617446f62d6Smrg } 1618446f62d6Smrg drmModeFreeProperty(props); 1619446f62d6Smrg } 1620446f62d6Smrg if (drmmode_output->tile_blob) { 1621446f62d6Smrg if (xf86OutputParseKMSTile(drmmode_output->tile_blob->data, 1622446f62d6Smrg drmmode_output->tile_blob->length, 1623446f62d6Smrg &tile_info) == TRUE) 1624446f62d6Smrg set = &tile_info; 1625446f62d6Smrg } 1626446f62d6Smrg xf86OutputSetTile(output, set); 1627446f62d6Smrg#endif 1628446f62d6Smrg} 1629446f62d6Smrg 16308bf5c682Smrgstatic int 16318bf5c682Smrgkoutput_get_prop_idx(int fd, drmModeConnectorPtr koutput, 16328bf5c682Smrg int type, const char *name) 16338bf5c682Smrg{ 16348bf5c682Smrg int idx = -1; 16358bf5c682Smrg 16368bf5c682Smrg for (int i = 0; i < koutput->count_props; i++) { 16378bf5c682Smrg drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]); 16388bf5c682Smrg 16398bf5c682Smrg if (!prop) 16408bf5c682Smrg continue; 16418bf5c682Smrg 16428bf5c682Smrg if (drm_property_type_is(prop, type) && !strcmp(prop->name, name)) 16438bf5c682Smrg idx = i; 16448bf5c682Smrg 16458bf5c682Smrg drmModeFreeProperty(prop); 16468bf5c682Smrg 16478bf5c682Smrg if (idx > -1) 16488bf5c682Smrg break; 16498bf5c682Smrg } 16508bf5c682Smrg 16518bf5c682Smrg return idx; 16528bf5c682Smrg} 16538bf5c682Smrg 16548bf5c682Smrgstatic int 16558bf5c682Smrgkoutput_get_prop_id(int fd, drmModeConnectorPtr koutput, 16568bf5c682Smrg int type, const char *name) 16578bf5c682Smrg{ 16588bf5c682Smrg int idx = koutput_get_prop_idx(fd, koutput, type, name); 16598bf5c682Smrg 16608bf5c682Smrg return (idx > -1) ? koutput->props[idx] : -1; 16618bf5c682Smrg} 16628bf5c682Smrg 16638bf5c682Smrgstatic drmModePropertyBlobPtr 16648bf5c682Smrgkoutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name) 16658bf5c682Smrg{ 16668bf5c682Smrg drmModePropertyBlobPtr blob = NULL; 16678bf5c682Smrg int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name); 16688bf5c682Smrg 16698bf5c682Smrg if (idx > -1) 16708bf5c682Smrg blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]); 16718bf5c682Smrg 16728bf5c682Smrg return blob; 16738bf5c682Smrg} 16748bf5c682Smrg 1675de2362d3Smrgstatic DisplayModePtr 1676de2362d3Smrgdrmmode_output_get_modes(xf86OutputPtr output) 1677de2362d3Smrg{ 1678de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1679de2362d3Smrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 16808bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 1681de2362d3Smrg int i; 1682de2362d3Smrg DisplayModePtr Modes = NULL, Mode; 1683de2362d3Smrg xf86MonPtr mon = NULL; 1684de2362d3Smrg 168518781e08Smrg if (!koutput) 168618781e08Smrg return NULL; 168718781e08Smrg 16888bf5c682Smrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 16898bf5c682Smrg 1690de2362d3Smrg /* look for an EDID property */ 16918bf5c682Smrg drmmode_output->edid_blob = 16928bf5c682Smrg koutput_get_prop_blob(pRADEONEnt->fd, koutput, "EDID"); 1693de2362d3Smrg 1694de2362d3Smrg if (drmmode_output->edid_blob) { 1695de2362d3Smrg mon = xf86InterpretEDID(output->scrn->scrnIndex, 1696de2362d3Smrg drmmode_output->edid_blob->data); 1697de2362d3Smrg if (mon && drmmode_output->edid_blob->length > 128) 1698de2362d3Smrg mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 1699de2362d3Smrg } 1700de2362d3Smrg xf86OutputSetEDID(output, mon); 1701de2362d3Smrg 1702446f62d6Smrg drmmode_output_attach_tile(output); 1703446f62d6Smrg 1704de2362d3Smrg /* modes should already be available */ 1705de2362d3Smrg for (i = 0; i < koutput->count_modes; i++) { 1706de2362d3Smrg Mode = xnfalloc(sizeof(DisplayModeRec)); 1707de2362d3Smrg 1708de2362d3Smrg drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode); 1709de2362d3Smrg Modes = xf86ModesAdd(Modes, Mode); 1710de2362d3Smrg 1711de2362d3Smrg } 1712de2362d3Smrg return Modes; 1713de2362d3Smrg} 1714de2362d3Smrg 1715de2362d3Smrgstatic void 1716de2362d3Smrgdrmmode_output_destroy(xf86OutputPtr output) 1717de2362d3Smrg{ 1718de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1719de2362d3Smrg int i; 1720de2362d3Smrg 1721446f62d6Smrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 1722446f62d6Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1, 17, 99, 901, 0) 1723446f62d6Smrg drmModeFreePropertyBlob(drmmode_output->tile_blob); 1724446f62d6Smrg#endif 1725446f62d6Smrg 1726de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 1727de2362d3Smrg drmModeFreeProperty(drmmode_output->props[i].mode_prop); 1728de2362d3Smrg free(drmmode_output->props[i].atoms); 1729de2362d3Smrg } 1730de2362d3Smrg for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) { 1731de2362d3Smrg drmModeFreeEncoder(drmmode_output->mode_encoders[i]); 1732de2362d3Smrg } 173318781e08Smrg free(drmmode_output->mode_encoders); 1734de2362d3Smrg free(drmmode_output->props); 1735de2362d3Smrg drmModeFreeConnector(drmmode_output->mode_output); 1736de2362d3Smrg free(drmmode_output); 1737de2362d3Smrg output->driver_private = NULL; 1738de2362d3Smrg} 1739de2362d3Smrg 1740de2362d3Smrgstatic void 1741de2362d3Smrgdrmmode_output_dpms(xf86OutputPtr output, int mode) 1742de2362d3Smrg{ 1743de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 174418781e08Smrg xf86CrtcPtr crtc = output->crtc; 1745de2362d3Smrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 17468bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 1747de2362d3Smrg 174818781e08Smrg if (!koutput) 174918781e08Smrg return; 175018781e08Smrg 17518bf5c682Smrg if (mode != DPMSModeOn && crtc) 175218781e08Smrg drmmode_do_crtc_dpms(crtc, mode); 175318781e08Smrg 17548bf5c682Smrg drmModeConnectorSetProperty(pRADEONEnt->fd, koutput->connector_id, 1755de2362d3Smrg drmmode_output->dpms_enum_id, mode); 175618781e08Smrg 175718781e08Smrg if (mode == DPMSModeOn && crtc) { 175818781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 175918781e08Smrg 176018781e08Smrg if (drmmode_crtc->need_modeset) 176118781e08Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x, 176218781e08Smrg crtc->y); 176318781e08Smrg else 176418781e08Smrg drmmode_do_crtc_dpms(crtc, mode); 176518781e08Smrg } 1766de2362d3Smrg} 1767de2362d3Smrg 1768de2362d3Smrg 1769de2362d3Smrgstatic Bool 1770de2362d3Smrgdrmmode_property_ignore(drmModePropertyPtr prop) 1771de2362d3Smrg{ 1772de2362d3Smrg if (!prop) 1773de2362d3Smrg return TRUE; 1774de2362d3Smrg /* ignore blob prop */ 1775de2362d3Smrg if (prop->flags & DRM_MODE_PROP_BLOB) 1776de2362d3Smrg return TRUE; 1777de2362d3Smrg /* ignore standard property */ 1778de2362d3Smrg if (!strcmp(prop->name, "EDID") || 1779de2362d3Smrg !strcmp(prop->name, "DPMS")) 1780de2362d3Smrg return TRUE; 1781de2362d3Smrg 1782de2362d3Smrg return FALSE; 1783de2362d3Smrg} 1784de2362d3Smrg 1785de2362d3Smrgstatic void 1786de2362d3Smrgdrmmode_output_create_resources(xf86OutputPtr output) 1787de2362d3Smrg{ 17883ed65abbSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1789de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1790de2362d3Smrg drmModeConnectorPtr mode_output = drmmode_output->mode_output; 17918bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 17923ed65abbSmrg drmModePropertyPtr drmmode_prop, tearfree_prop; 1793de2362d3Smrg int i, j, err; 179439413783Smrg Atom name; 179539413783Smrg 179639413783Smrg /* Create CONNECTOR_ID property */ 179739413783Smrg name = MakeAtom("CONNECTOR_ID", 12, TRUE); 179839413783Smrg if (name != BAD_RESOURCE) { 179939413783Smrg INT32 value = mode_output->connector_id; 180039413783Smrg 180139413783Smrg err = RRConfigureOutputProperty(output->randr_output, name, 180239413783Smrg FALSE, FALSE, TRUE, 1, &value); 180339413783Smrg if (err != Success) { 180439413783Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 180539413783Smrg "RRConfigureOutputProperty error, %d\n", err); 180639413783Smrg } 180739413783Smrg 180839413783Smrg err = RRChangeOutputProperty(output->randr_output, name, 180939413783Smrg XA_INTEGER, 32, PropModeReplace, 1, 181039413783Smrg &value, FALSE, FALSE); 181139413783Smrg if (err != Success) { 181239413783Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 181339413783Smrg "RRChangeOutputProperty error, %d\n", err); 181439413783Smrg } 181539413783Smrg } 1816de2362d3Smrg 18173ed65abbSmrg drmmode_output->props = calloc(mode_output->count_props + 1, sizeof(drmmode_prop_rec)); 1818de2362d3Smrg if (!drmmode_output->props) 1819de2362d3Smrg return; 1820de2362d3Smrg 1821de2362d3Smrg drmmode_output->num_props = 0; 1822de2362d3Smrg for (i = 0, j = 0; i < mode_output->count_props; i++) { 18238bf5c682Smrg drmmode_prop = drmModeGetProperty(pRADEONEnt->fd, mode_output->props[i]); 1824de2362d3Smrg if (drmmode_property_ignore(drmmode_prop)) { 1825de2362d3Smrg drmModeFreeProperty(drmmode_prop); 1826de2362d3Smrg continue; 1827de2362d3Smrg } 1828de2362d3Smrg drmmode_output->props[j].mode_prop = drmmode_prop; 1829de2362d3Smrg drmmode_output->props[j].value = mode_output->prop_values[i]; 1830de2362d3Smrg drmmode_output->num_props++; 1831de2362d3Smrg j++; 1832de2362d3Smrg } 1833de2362d3Smrg 18343ed65abbSmrg /* Userspace-only property for TearFree */ 18353ed65abbSmrg tearfree_prop = calloc(1, sizeof(*tearfree_prop)); 18363ed65abbSmrg tearfree_prop->flags = DRM_MODE_PROP_ENUM; 183739413783Smrg strcpy(tearfree_prop->name, "TearFree"); 18383ed65abbSmrg tearfree_prop->count_enums = 3; 18393ed65abbSmrg tearfree_prop->enums = calloc(tearfree_prop->count_enums, 18403ed65abbSmrg sizeof(*tearfree_prop->enums)); 184139413783Smrg strcpy(tearfree_prop->enums[0].name, "off"); 184239413783Smrg strcpy(tearfree_prop->enums[1].name, "on"); 18433ed65abbSmrg tearfree_prop->enums[1].value = 1; 184439413783Smrg strcpy(tearfree_prop->enums[2].name, "auto"); 18453ed65abbSmrg tearfree_prop->enums[2].value = 2; 18463ed65abbSmrg drmmode_output->props[j].mode_prop = tearfree_prop; 18473ed65abbSmrg drmmode_output->props[j].value = info->tear_free; 18483ed65abbSmrg drmmode_output->tear_free = info->tear_free; 18493ed65abbSmrg drmmode_output->num_props++; 18503ed65abbSmrg 1851de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 1852de2362d3Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 1853de2362d3Smrg drmmode_prop = p->mode_prop; 1854de2362d3Smrg 1855de2362d3Smrg if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 1856de2362d3Smrg INT32 range[2]; 1857de2362d3Smrg INT32 value = p->value; 1858de2362d3Smrg 1859de2362d3Smrg p->num_atoms = 1; 1860de2362d3Smrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 1861de2362d3Smrg if (!p->atoms) 1862de2362d3Smrg continue; 1863de2362d3Smrg p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 1864de2362d3Smrg range[0] = drmmode_prop->values[0]; 1865de2362d3Smrg range[1] = drmmode_prop->values[1]; 1866de2362d3Smrg err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 1867de2362d3Smrg FALSE, TRUE, 1868de2362d3Smrg drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 1869de2362d3Smrg 2, range); 1870de2362d3Smrg if (err != 0) { 1871de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1872de2362d3Smrg "RRConfigureOutputProperty error, %d\n", err); 1873de2362d3Smrg } 1874de2362d3Smrg err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 1875de2362d3Smrg XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, TRUE); 1876de2362d3Smrg if (err != 0) { 1877de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1878de2362d3Smrg "RRChangeOutputProperty error, %d\n", err); 1879de2362d3Smrg } 1880de2362d3Smrg } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 1881de2362d3Smrg p->num_atoms = drmmode_prop->count_enums + 1; 1882de2362d3Smrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 1883de2362d3Smrg if (!p->atoms) 1884de2362d3Smrg continue; 1885de2362d3Smrg p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 1886de2362d3Smrg for (j = 1; j <= drmmode_prop->count_enums; j++) { 1887de2362d3Smrg struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; 1888de2362d3Smrg p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); 1889de2362d3Smrg } 1890de2362d3Smrg err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 1891de2362d3Smrg FALSE, FALSE, 1892de2362d3Smrg drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 1893de2362d3Smrg p->num_atoms - 1, (INT32 *)&p->atoms[1]); 1894de2362d3Smrg if (err != 0) { 1895de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1896de2362d3Smrg "RRConfigureOutputProperty error, %d\n", err); 1897de2362d3Smrg } 1898de2362d3Smrg for (j = 0; j < drmmode_prop->count_enums; j++) 1899de2362d3Smrg if (drmmode_prop->enums[j].value == p->value) 1900de2362d3Smrg break; 1901de2362d3Smrg /* there's always a matching value */ 1902de2362d3Smrg err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 1903de2362d3Smrg XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE); 1904de2362d3Smrg if (err != 0) { 1905de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1906de2362d3Smrg "RRChangeOutputProperty error, %d\n", err); 1907de2362d3Smrg } 1908de2362d3Smrg } 1909de2362d3Smrg } 1910de2362d3Smrg} 1911de2362d3Smrg 191239413783Smrgstatic void 191339413783Smrgdrmmode_output_set_tear_free(RADEONEntPtr pRADEONEnt, 191439413783Smrg drmmode_output_private_ptr drmmode_output, 191539413783Smrg xf86CrtcPtr crtc, int tear_free) 191639413783Smrg{ 191739413783Smrg if (drmmode_output->tear_free == tear_free) 191839413783Smrg return; 191939413783Smrg 192039413783Smrg drmmode_output->tear_free = tear_free; 192139413783Smrg 192239413783Smrg if (crtc) { 192339413783Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 192439413783Smrg crtc->x, crtc->y); 192539413783Smrg } 192639413783Smrg} 192739413783Smrg 1928de2362d3Smrgstatic Bool 1929de2362d3Smrgdrmmode_output_set_property(xf86OutputPtr output, Atom property, 1930de2362d3Smrg RRPropertyValuePtr value) 1931de2362d3Smrg{ 1932de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 19338bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 1934de2362d3Smrg int i; 1935de2362d3Smrg 1936de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 1937de2362d3Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 1938de2362d3Smrg 1939de2362d3Smrg if (p->atoms[0] != property) 1940de2362d3Smrg continue; 1941de2362d3Smrg 1942de2362d3Smrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 1943de2362d3Smrg uint32_t val; 1944de2362d3Smrg 1945de2362d3Smrg if (value->type != XA_INTEGER || value->format != 32 || 1946de2362d3Smrg value->size != 1) 1947de2362d3Smrg return FALSE; 1948de2362d3Smrg val = *(uint32_t *)value->data; 1949de2362d3Smrg 19508bf5c682Smrg drmModeConnectorSetProperty(pRADEONEnt->fd, drmmode_output->output_id, 1951de2362d3Smrg p->mode_prop->prop_id, (uint64_t)val); 1952de2362d3Smrg return TRUE; 1953de2362d3Smrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 1954de2362d3Smrg Atom atom; 1955de2362d3Smrg const char *name; 1956de2362d3Smrg int j; 1957de2362d3Smrg 1958de2362d3Smrg if (value->type != XA_ATOM || value->format != 32 || value->size != 1) 1959de2362d3Smrg return FALSE; 1960de2362d3Smrg memcpy(&atom, value->data, 4); 19618bf5c682Smrg if (!(name = NameForAtom(atom))) 19628bf5c682Smrg return FALSE; 1963de2362d3Smrg 1964de2362d3Smrg /* search for matching name string, then set its value down */ 1965de2362d3Smrg for (j = 0; j < p->mode_prop->count_enums; j++) { 1966de2362d3Smrg if (!strcmp(p->mode_prop->enums[j].name, name)) { 19673ed65abbSmrg if (i == (drmmode_output->num_props - 1)) { 196839413783Smrg drmmode_output_set_tear_free(pRADEONEnt, drmmode_output, 196939413783Smrg output->crtc, j); 19703ed65abbSmrg } else { 19718bf5c682Smrg drmModeConnectorSetProperty(pRADEONEnt->fd, 19723ed65abbSmrg drmmode_output->output_id, 19733ed65abbSmrg p->mode_prop->prop_id, 19743ed65abbSmrg p->mode_prop->enums[j].value); 19753ed65abbSmrg } 19763ed65abbSmrg 1977de2362d3Smrg return TRUE; 1978de2362d3Smrg } 1979de2362d3Smrg } 1980de2362d3Smrg } 1981de2362d3Smrg } 1982de2362d3Smrg 1983de2362d3Smrg return TRUE; 1984de2362d3Smrg} 1985de2362d3Smrg 1986de2362d3Smrgstatic Bool 1987de2362d3Smrgdrmmode_output_get_property(xf86OutputPtr output, Atom property) 1988de2362d3Smrg{ 1989de2362d3Smrg return TRUE; 1990de2362d3Smrg} 1991de2362d3Smrg 1992de2362d3Smrgstatic const xf86OutputFuncsRec drmmode_output_funcs = { 1993de2362d3Smrg .dpms = drmmode_output_dpms, 1994de2362d3Smrg .create_resources = drmmode_output_create_resources, 1995de2362d3Smrg .set_property = drmmode_output_set_property, 1996de2362d3Smrg .get_property = drmmode_output_get_property, 1997de2362d3Smrg .detect = drmmode_output_detect, 1998de2362d3Smrg .mode_valid = drmmode_output_mode_valid, 1999de2362d3Smrg 2000de2362d3Smrg .get_modes = drmmode_output_get_modes, 2001de2362d3Smrg .destroy = drmmode_output_destroy 2002de2362d3Smrg}; 2003de2362d3Smrg 2004de2362d3Smrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown, 2005de2362d3Smrg SubPixelHorizontalRGB, 2006de2362d3Smrg SubPixelHorizontalBGR, 2007de2362d3Smrg SubPixelVerticalRGB, 2008de2362d3Smrg SubPixelVerticalBGR, 2009de2362d3Smrg SubPixelNone }; 2010de2362d3Smrg 2011de2362d3Smrgconst char *output_names[] = { "None", 2012de2362d3Smrg "VGA", 2013de2362d3Smrg "DVI", 2014de2362d3Smrg "DVI", 2015de2362d3Smrg "DVI", 2016de2362d3Smrg "Composite", 2017de2362d3Smrg "S-video", 2018de2362d3Smrg "LVDS", 2019de2362d3Smrg "CTV", 2020de2362d3Smrg "DIN", 2021de2362d3Smrg "DisplayPort", 2022de2362d3Smrg "HDMI", 2023de2362d3Smrg "HDMI", 2024de2362d3Smrg "TV", 2025de2362d3Smrg "eDP" 2026de2362d3Smrg}; 2027de2362d3Smrg 202818781e08Smrg#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0])) 202918781e08Smrg 203018781e08Smrgstatic xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id) 203118781e08Smrg{ 203218781e08Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 203318781e08Smrg int i; 203418781e08Smrg for (i = 0; i < xf86_config->num_output; i++) { 203518781e08Smrg xf86OutputPtr output = xf86_config->output[i]; 203618781e08Smrg drmmode_output_private_ptr drmmode_output; 203718781e08Smrg 203818781e08Smrg drmmode_output = output->driver_private; 203918781e08Smrg if (drmmode_output->output_id == id) 204018781e08Smrg return output; 204118781e08Smrg } 204218781e08Smrg return NULL; 204318781e08Smrg} 204418781e08Smrg 204518781e08Smrgstatic int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path) 204618781e08Smrg{ 204718781e08Smrg char *conn; 204818781e08Smrg char conn_id[5]; 204918781e08Smrg int id, len; 205018781e08Smrg char *blob_data; 205118781e08Smrg 205218781e08Smrg if (!path_blob) 205318781e08Smrg return -1; 205418781e08Smrg 205518781e08Smrg blob_data = path_blob->data; 205618781e08Smrg /* we only handle MST paths for now */ 205718781e08Smrg if (strncmp(blob_data, "mst:", 4)) 205818781e08Smrg return -1; 205918781e08Smrg 206018781e08Smrg conn = strchr(blob_data + 4, '-'); 206118781e08Smrg if (!conn) 206218781e08Smrg return -1; 206318781e08Smrg len = conn - (blob_data + 4); 206418781e08Smrg if (len + 1 > 5) 206518781e08Smrg return -1; 206618781e08Smrg memcpy(conn_id, blob_data + 4, len); 206718781e08Smrg conn_id[len] = '\0'; 206818781e08Smrg id = strtoul(conn_id, NULL, 10); 206918781e08Smrg 207018781e08Smrg *conn_base_id = id; 207118781e08Smrg 207218781e08Smrg *path = conn + 1; 207318781e08Smrg return 0; 207418781e08Smrg} 207518781e08Smrg 2076de2362d3Smrgstatic void 207718781e08Smrgdrmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name, 207818781e08Smrg drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi) 207918781e08Smrg{ 208018781e08Smrg xf86OutputPtr output; 208118781e08Smrg int conn_id; 208218781e08Smrg char *extra_path; 208318781e08Smrg 208418781e08Smrg output = NULL; 208518781e08Smrg if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0) 208618781e08Smrg output = find_output(pScrn, conn_id); 208718781e08Smrg if (output) { 208818781e08Smrg snprintf(name, 32, "%s-%s", output->name, extra_path); 208918781e08Smrg } else { 20908bf5c682Smrg if (koutput->connector_type >= NUM_OUTPUT_NAMES) { 209118781e08Smrg snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, 209218781e08Smrg koutput->connector_type_id - 1); 20938bf5c682Smrg } else if (pScrn->is_gpu) { 209418781e08Smrg snprintf(name, 32, "%s-%d-%d", 209518781e08Smrg output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, 209618781e08Smrg koutput->connector_type_id - 1); 20978bf5c682Smrg } else { 209818781e08Smrg /* need to do smart conversion here for compat with non-kms ATI driver */ 209918781e08Smrg if (koutput->connector_type_id == 1) { 210018781e08Smrg switch(koutput->connector_type) { 210118781e08Smrg case DRM_MODE_CONNECTOR_DVII: 210218781e08Smrg case DRM_MODE_CONNECTOR_DVID: 210318781e08Smrg case DRM_MODE_CONNECTOR_DVIA: 210418781e08Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi); 210518781e08Smrg (*num_dvi)++; 210618781e08Smrg break; 210718781e08Smrg case DRM_MODE_CONNECTOR_HDMIA: 210818781e08Smrg case DRM_MODE_CONNECTOR_HDMIB: 210918781e08Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi); 211018781e08Smrg (*num_hdmi)++; 211118781e08Smrg break; 211218781e08Smrg case DRM_MODE_CONNECTOR_VGA: 211318781e08Smrg case DRM_MODE_CONNECTOR_DisplayPort: 211418781e08Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], 211518781e08Smrg koutput->connector_type_id - 1); 211618781e08Smrg break; 211718781e08Smrg default: 211818781e08Smrg snprintf(name, 32, "%s", output_names[koutput->connector_type]); 211918781e08Smrg break; 212018781e08Smrg } 212118781e08Smrg } else { 212218781e08Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], 212318781e08Smrg koutput->connector_type_id - 1); 212418781e08Smrg } 212518781e08Smrg } 212618781e08Smrg } 212718781e08Smrg} 212818781e08Smrg 212918781e08Smrgstatic unsigned int 213018781e08Smrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic) 21310d16fef4Smrg{ 213218781e08Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 21338bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 2134de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 2135de2362d3Smrg xf86OutputPtr output; 2136de2362d3Smrg drmModeConnectorPtr koutput; 2137de2362d3Smrg drmModeEncoderPtr *kencoders = NULL; 2138de2362d3Smrg drmmode_output_private_ptr drmmode_output; 213918781e08Smrg drmModePropertyBlobPtr path_blob = NULL; 214039413783Smrg#if XF86_CRTC_VERSION >= 8 214139413783Smrg Bool nonDesktop = FALSE; 214239413783Smrg#endif 2143de2362d3Smrg char name[32]; 2144de2362d3Smrg int i; 2145de2362d3Smrg const char *s; 2146de2362d3Smrg 21478bf5c682Smrg koutput = drmModeGetConnector(pRADEONEnt->fd, mode_res->connectors[num]); 2148de2362d3Smrg if (!koutput) 214918781e08Smrg return 0; 215018781e08Smrg 21518bf5c682Smrg path_blob = koutput_get_prop_blob(pRADEONEnt->fd, koutput, "PATH"); 2152de2362d3Smrg 215339413783Smrg#if XF86_CRTC_VERSION >= 8 215439413783Smrg i = koutput_get_prop_idx(pRADEONEnt->fd, koutput, DRM_MODE_PROP_RANGE, 215539413783Smrg "non-desktop"); 215639413783Smrg if (i >= 0) 215739413783Smrg nonDesktop = koutput->prop_values[i] != 0; 215839413783Smrg#endif 215939413783Smrg 2160de2362d3Smrg kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); 2161de2362d3Smrg if (!kencoders) { 2162de2362d3Smrg goto out_free_encoders; 2163de2362d3Smrg } 2164de2362d3Smrg 2165de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) { 21668bf5c682Smrg kencoders[i] = drmModeGetEncoder(pRADEONEnt->fd, koutput->encoders[i]); 2167de2362d3Smrg if (!kencoders[i]) { 2168de2362d3Smrg goto out_free_encoders; 2169de2362d3Smrg } 2170de2362d3Smrg } 2171de2362d3Smrg 217218781e08Smrg drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi); 217318781e08Smrg if (path_blob) 217418781e08Smrg drmModeFreePropertyBlob(path_blob); 217518781e08Smrg 217618781e08Smrg if (path_blob && dynamic) { 217718781e08Smrg /* See if we have an output with this name already 217818781e08Smrg * and hook stuff up. 217918781e08Smrg */ 218018781e08Smrg for (i = 0; i < xf86_config->num_output; i++) { 218118781e08Smrg output = xf86_config->output[i]; 218218781e08Smrg 218318781e08Smrg if (strncmp(output->name, name, 32)) 218418781e08Smrg continue; 218518781e08Smrg 218618781e08Smrg drmmode_output = output->driver_private; 218718781e08Smrg drmmode_output->output_id = mode_res->connectors[num]; 218818781e08Smrg drmmode_output->mode_output = koutput; 218939413783Smrg#if XF86_CRTC_VERSION >= 8 219039413783Smrg output->non_desktop = nonDesktop; 219139413783Smrg#endif 219218781e08Smrg for (i = 0; i < koutput->count_encoders; i++) 219318781e08Smrg drmModeFreeEncoder(kencoders[i]); 219418781e08Smrg free(kencoders); 219518781e08Smrg return 0; 219618781e08Smrg } 2197de2362d3Smrg } 2198de2362d3Smrg 2199de2362d3Smrg if (xf86IsEntityShared(pScrn->entityList[0])) { 2200de2362d3Smrg if ((s = xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) { 2201de2362d3Smrg if (!RADEONZaphodStringMatches(pScrn, s, name)) 2202de2362d3Smrg goto out_free_encoders; 2203de2362d3Smrg } else { 2204446f62d6Smrg if (info->instance_id != num) 2205de2362d3Smrg goto out_free_encoders; 2206de2362d3Smrg } 2207de2362d3Smrg } 2208de2362d3Smrg 2209de2362d3Smrg output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name); 2210de2362d3Smrg if (!output) { 2211de2362d3Smrg goto out_free_encoders; 2212de2362d3Smrg } 2213de2362d3Smrg 2214de2362d3Smrg drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); 2215de2362d3Smrg if (!drmmode_output) { 2216de2362d3Smrg xf86OutputDestroy(output); 2217de2362d3Smrg goto out_free_encoders; 2218de2362d3Smrg } 2219de2362d3Smrg 222018781e08Smrg drmmode_output->output_id = mode_res->connectors[num]; 2221de2362d3Smrg drmmode_output->mode_output = koutput; 2222de2362d3Smrg drmmode_output->mode_encoders = kencoders; 2223de2362d3Smrg drmmode_output->drmmode = drmmode; 2224de2362d3Smrg output->mm_width = koutput->mmWidth; 2225de2362d3Smrg output->mm_height = koutput->mmHeight; 2226de2362d3Smrg 2227de2362d3Smrg output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 2228de2362d3Smrg output->interlaceAllowed = TRUE; 2229de2362d3Smrg output->doubleScanAllowed = TRUE; 2230de2362d3Smrg output->driver_private = drmmode_output; 223139413783Smrg#if XF86_CRTC_VERSION >= 8 223239413783Smrg output->non_desktop = nonDesktop; 223339413783Smrg#endif 2234de2362d3Smrg 2235de2362d3Smrg output->possible_crtcs = 0xffffffff; 2236de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) { 2237de2362d3Smrg output->possible_crtcs &= kencoders[i]->possible_crtcs; 2238de2362d3Smrg } 2239de2362d3Smrg /* work out the possible clones later */ 2240de2362d3Smrg output->possible_clones = 0; 2241de2362d3Smrg 22428bf5c682Smrg drmmode_output->dpms_enum_id = 22438bf5c682Smrg koutput_get_prop_id(pRADEONEnt->fd, koutput, DRM_MODE_PROP_ENUM, 22448bf5c682Smrg "DPMS"); 2245de2362d3Smrg 224618781e08Smrg if (dynamic) { 224718781e08Smrg output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output); 224818781e08Smrg drmmode_output_create_resources(output); 224918781e08Smrg } 225018781e08Smrg 225118781e08Smrg return 1; 2252de2362d3Smrgout_free_encoders: 2253de2362d3Smrg if (kencoders){ 2254de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) 2255de2362d3Smrg drmModeFreeEncoder(kencoders[i]); 2256de2362d3Smrg free(kencoders); 2257de2362d3Smrg } 2258de2362d3Smrg drmModeFreeConnector(koutput); 225918781e08Smrg return 0; 2260de2362d3Smrg} 2261de2362d3Smrg 2262de2362d3Smrguint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output) 2263de2362d3Smrg{ 2264de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private, clone_drmout; 2265de2362d3Smrg int i; 2266de2362d3Smrg xf86OutputPtr clone_output; 2267de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2268de2362d3Smrg int index_mask = 0; 2269de2362d3Smrg 2270de2362d3Smrg if (drmmode_output->enc_clone_mask == 0) 2271de2362d3Smrg return index_mask; 2272de2362d3Smrg 2273de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 2274de2362d3Smrg clone_output = xf86_config->output[i]; 2275de2362d3Smrg clone_drmout = clone_output->driver_private; 2276de2362d3Smrg if (output == clone_output) 2277de2362d3Smrg continue; 2278de2362d3Smrg 2279de2362d3Smrg if (clone_drmout->enc_mask == 0) 2280de2362d3Smrg continue; 2281de2362d3Smrg if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask) 2282de2362d3Smrg index_mask |= (1 << i); 2283de2362d3Smrg } 2284de2362d3Smrg return index_mask; 2285de2362d3Smrg} 2286de2362d3Smrg 2287de2362d3Smrg 2288de2362d3Smrgstatic void 228918781e08Smrgdrmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res) 2290de2362d3Smrg{ 2291de2362d3Smrg int i, j; 2292de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2293de2362d3Smrg 2294de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 2295de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 2296de2362d3Smrg drmmode_output_private_ptr drmmode_output; 2297de2362d3Smrg 2298de2362d3Smrg drmmode_output = output->driver_private; 2299de2362d3Smrg drmmode_output->enc_clone_mask = 0xff; 2300de2362d3Smrg /* and all the possible encoder clones for this output together */ 2301de2362d3Smrg for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) 2302de2362d3Smrg { 2303de2362d3Smrg int k; 230418781e08Smrg for (k = 0; k < mode_res->count_encoders; k++) { 230518781e08Smrg if (mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id) 2306de2362d3Smrg drmmode_output->enc_mask |= (1 << k); 2307de2362d3Smrg } 2308de2362d3Smrg 2309de2362d3Smrg drmmode_output->enc_clone_mask &= drmmode_output->mode_encoders[j]->possible_clones; 2310de2362d3Smrg } 2311de2362d3Smrg } 2312de2362d3Smrg 2313de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 2314de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 2315de2362d3Smrg output->possible_clones = find_clones(scrn, output); 2316de2362d3Smrg } 2317de2362d3Smrg} 2318de2362d3Smrg 2319de2362d3Smrg/* returns height alignment in pixels */ 2320de2362d3Smrgint drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling) 2321de2362d3Smrg{ 2322de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 2323de2362d3Smrg int height_align = 1; 2324de2362d3Smrg 2325de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 2326de2362d3Smrg if (tiling & RADEON_TILING_MACRO) 2327de2362d3Smrg height_align = info->num_channels * 8; 2328de2362d3Smrg else if (tiling & RADEON_TILING_MICRO) 2329de2362d3Smrg height_align = 8; 2330de2362d3Smrg else 2331de2362d3Smrg height_align = 8; 2332de2362d3Smrg } else { 233318781e08Smrg if (tiling & RADEON_TILING_MICRO_SQUARE) 233418781e08Smrg height_align = 32; 233518781e08Smrg else if (tiling) 2336de2362d3Smrg height_align = 16; 2337de2362d3Smrg else 2338de2362d3Smrg height_align = 1; 2339de2362d3Smrg } 2340de2362d3Smrg return height_align; 2341de2362d3Smrg} 2342de2362d3Smrg 2343de2362d3Smrg/* returns pitch alignment in pixels */ 2344de2362d3Smrgint drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling) 2345de2362d3Smrg{ 2346de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 2347de2362d3Smrg int pitch_align = 1; 2348de2362d3Smrg 2349de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 2350de2362d3Smrg if (tiling & RADEON_TILING_MACRO) { 2351de2362d3Smrg /* general surface requirements */ 2352de2362d3Smrg pitch_align = MAX(info->num_banks, 2353de2362d3Smrg (((info->group_bytes / 8) / bpe) * info->num_banks)) * 8; 2354de2362d3Smrg /* further restrictions for scanout */ 2355de2362d3Smrg pitch_align = MAX(info->num_banks * 8, pitch_align); 2356de2362d3Smrg } else if (tiling & RADEON_TILING_MICRO) { 2357de2362d3Smrg /* general surface requirements */ 2358de2362d3Smrg pitch_align = MAX(8, (info->group_bytes / (8 * bpe))); 2359de2362d3Smrg /* further restrictions for scanout */ 2360de2362d3Smrg pitch_align = MAX(info->group_bytes / bpe, pitch_align); 2361de2362d3Smrg } else { 2362de2362d3Smrg if (info->have_tiling_info) 2363de2362d3Smrg /* linear aligned requirements */ 2364de2362d3Smrg pitch_align = MAX(64, info->group_bytes / bpe); 2365de2362d3Smrg else 2366de2362d3Smrg /* default to 512 elements if we don't know the real 2367de2362d3Smrg * group size otherwise the kernel may reject the CS 2368de2362d3Smrg * if the group sizes don't match as the pitch won't 2369de2362d3Smrg * be aligned properly. 2370de2362d3Smrg */ 2371de2362d3Smrg pitch_align = 512; 2372de2362d3Smrg } 2373de2362d3Smrg } else { 2374de2362d3Smrg /* general surface requirements */ 2375de2362d3Smrg if (tiling) 2376de2362d3Smrg pitch_align = 256 / bpe; 2377de2362d3Smrg else 2378de2362d3Smrg pitch_align = 64; 2379de2362d3Smrg } 2380de2362d3Smrg return pitch_align; 2381de2362d3Smrg} 2382de2362d3Smrg 2383de2362d3Smrg/* returns base alignment in bytes */ 2384de2362d3Smrgint drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling) 2385de2362d3Smrg{ 2386de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 2387de2362d3Smrg int pixel_align = drmmode_get_pitch_align(scrn, bpe, tiling); 2388de2362d3Smrg int height_align = drmmode_get_height_align(scrn, tiling); 2389de2362d3Smrg int base_align = RADEON_GPU_PAGE_SIZE; 2390de2362d3Smrg 2391de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 2392de2362d3Smrg if (tiling & RADEON_TILING_MACRO) 2393de2362d3Smrg base_align = MAX(info->num_banks * info->num_channels * 8 * 8 * bpe, 2394de2362d3Smrg pixel_align * bpe * height_align); 2395de2362d3Smrg else { 2396de2362d3Smrg if (info->have_tiling_info) 2397de2362d3Smrg base_align = info->group_bytes; 2398de2362d3Smrg else 2399de2362d3Smrg /* default to 512 if we don't know the real 2400de2362d3Smrg * group size otherwise the kernel may reject the CS 2401de2362d3Smrg * if the group sizes don't match as the base won't 2402de2362d3Smrg * be aligned properly. 2403de2362d3Smrg */ 2404de2362d3Smrg base_align = 512; 2405de2362d3Smrg } 2406de2362d3Smrg } 2407de2362d3Smrg return base_align; 2408de2362d3Smrg} 2409de2362d3Smrg 2410de2362d3Smrgstatic Bool 2411de2362d3Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) 2412de2362d3Smrg{ 2413de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2414de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 241539413783Smrg struct radeon_buffer *old_front = NULL; 2416de2362d3Smrg ScreenPtr screen = xf86ScrnToScreen(scrn); 2417de2362d3Smrg int i, pitch, old_width, old_height, old_pitch; 241839413783Smrg int usage = CREATE_PIXMAP_USAGE_BACKING_PIXMAP; 241918781e08Smrg int cpp = info->pixel_bytes; 242039413783Smrg uint32_t tiling_flags; 2421de2362d3Smrg PixmapPtr ppix = screen->GetScreenPixmap(screen); 2422de2362d3Smrg void *fb_shadow; 2423de2362d3Smrg 2424de2362d3Smrg if (scrn->virtualX == width && scrn->virtualY == height) 2425de2362d3Smrg return TRUE; 2426de2362d3Smrg 242739413783Smrg if (width > xf86_config->maxWidth || height > xf86_config->maxHeight) { 242839413783Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 242939413783Smrg "Xorg tried resizing screen to %dx%d, but maximum " 243039413783Smrg "supported is %dx%d\n", width, height, 243139413783Smrg xf86_config->maxWidth, xf86_config->maxHeight); 243239413783Smrg return FALSE; 2433de2362d3Smrg } 2434de2362d3Smrg 243539413783Smrg if (info->allowColorTiling && !info->shadow_primary) { 243639413783Smrg if (info->ChipFamily < CHIP_FAMILY_R600 || info->allowColorTiling2D) 243739413783Smrg usage |= RADEON_CREATE_PIXMAP_TILING_MACRO; 243839413783Smrg else 243939413783Smrg usage |= RADEON_CREATE_PIXMAP_TILING_MICRO; 2440de2362d3Smrg } 2441de2362d3Smrg 244239413783Smrg xf86DrvMsg(scrn->scrnIndex, X_INFO, "Allocate new frame buffer %dx%d\n", 244339413783Smrg width, height); 2444de2362d3Smrg 2445de2362d3Smrg old_width = scrn->virtualX; 2446de2362d3Smrg old_height = scrn->virtualY; 2447de2362d3Smrg old_pitch = scrn->displayWidth; 244839413783Smrg old_front = info->front_buffer; 2449de2362d3Smrg 2450de2362d3Smrg scrn->virtualX = width; 2451de2362d3Smrg scrn->virtualY = height; 2452de2362d3Smrg 245339413783Smrg info->front_buffer = radeon_alloc_pixmap_bo(scrn, scrn->virtualX, 245439413783Smrg scrn->virtualY, scrn->depth, 245539413783Smrg usage, scrn->bitsPerPixel, 245639413783Smrg &pitch, 245739413783Smrg &info->front_surface, 245839413783Smrg &tiling_flags); 245939413783Smrg if (!info->front_buffer) 2460de2362d3Smrg goto fail; 2461de2362d3Smrg 246239413783Smrg scrn->displayWidth = pitch / cpp; 246339413783Smrg 246439413783Smrg if (!info->use_glamor) { 2465de2362d3Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN 246639413783Smrg switch (cpp) { 246739413783Smrg case 4: 246839413783Smrg tiling_flags |= RADEON_TILING_SWAP_32BIT; 246939413783Smrg break; 247039413783Smrg case 2: 247139413783Smrg tiling_flags |= RADEON_TILING_SWAP_16BIT; 247239413783Smrg break; 247339413783Smrg } 247439413783Smrg if (info->ChipFamily < CHIP_FAMILY_R600 && 247539413783Smrg info->r600_shadow_fb && tiling_flags) 247639413783Smrg tiling_flags |= RADEON_TILING_SURFACE; 2477de2362d3Smrg#endif 247839413783Smrg if (tiling_flags) 247939413783Smrg radeon_bo_set_tiling(info->front_buffer->bo.radeon, tiling_flags, pitch); 248039413783Smrg } 2481de2362d3Smrg 2482de2362d3Smrg if (!info->r600_shadow_fb) { 248339413783Smrg if (info->surf_man && !info->use_glamor) 248439413783Smrg *radeon_get_pixmap_surface(ppix) = info->front_surface; 2485de2362d3Smrg screen->ModifyPixmapHeader(ppix, 2486de2362d3Smrg width, height, -1, -1, pitch, NULL); 2487de2362d3Smrg } else { 248839413783Smrg if (radeon_bo_map(info->front_buffer->bo.radeon, 1)) 2489de2362d3Smrg goto fail; 249039413783Smrg fb_shadow = calloc(1, pitch * scrn->virtualY); 249139413783Smrg if (!fb_shadow) 2492de2362d3Smrg goto fail; 2493de2362d3Smrg free(info->fb_shadow); 2494de2362d3Smrg info->fb_shadow = fb_shadow; 2495de2362d3Smrg screen->ModifyPixmapHeader(ppix, 2496de2362d3Smrg width, height, -1, -1, pitch, 2497de2362d3Smrg info->fb_shadow); 2498de2362d3Smrg } 249918781e08Smrg 250018781e08Smrg if (info->use_glamor) 250118781e08Smrg radeon_glamor_create_screen_resources(scrn->pScreen); 250218781e08Smrg 250318781e08Smrg if (!info->r600_shadow_fb) { 250439413783Smrg if (!radeon_set_pixmap_bo(ppix, info->front_buffer)) 250518781e08Smrg goto fail; 250618781e08Smrg } 250718781e08Smrg 25088bf5c682Smrg radeon_pixmap_clear(ppix); 250939413783Smrg radeon_finish(scrn, info->front_buffer); 25100d16fef4Smrg 2511de2362d3Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 2512de2362d3Smrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 2513de2362d3Smrg 2514de2362d3Smrg if (!crtc->enabled) 2515de2362d3Smrg continue; 2516de2362d3Smrg 2517de2362d3Smrg drmmode_set_mode_major(crtc, &crtc->mode, 2518de2362d3Smrg crtc->rotation, crtc->x, crtc->y); 2519de2362d3Smrg } 2520de2362d3Smrg 252139413783Smrg radeon_buffer_unref(&old_front); 2522de2362d3Smrg 252339413783Smrg radeon_kms_update_vram_limit(scrn, pitch * scrn->virtualY); 2524de2362d3Smrg return TRUE; 2525de2362d3Smrg 2526de2362d3Smrg fail: 252739413783Smrg radeon_buffer_unref(&info->front_buffer); 252839413783Smrg info->front_buffer = old_front; 2529de2362d3Smrg scrn->virtualX = old_width; 2530de2362d3Smrg scrn->virtualY = old_height; 2531de2362d3Smrg scrn->displayWidth = old_pitch; 2532de2362d3Smrg 2533de2362d3Smrg return FALSE; 2534de2362d3Smrg} 2535de2362d3Smrg 253639413783Smrgstatic void 253739413783Smrgdrmmode_validate_leases(ScrnInfoPtr scrn) 253839413783Smrg{ 253939413783Smrg#ifdef XF86_LEASE_VERSION 254039413783Smrg ScreenPtr screen = scrn->pScreen; 254139413783Smrg rrScrPrivPtr scr_priv = rrGetScrPriv(screen); 254239413783Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 254339413783Smrg drmModeLesseeListPtr lessees; 254439413783Smrg RRLeasePtr lease, next; 254539413783Smrg int l; 254639413783Smrg 254739413783Smrg /* We can't talk to the kernel about leases when VT switched */ 254839413783Smrg if (!scrn->vtSema) 254939413783Smrg return; 255039413783Smrg 255139413783Smrg lessees = drmModeListLessees(pRADEONEnt->fd); 255239413783Smrg if (!lessees) 255339413783Smrg return; 255439413783Smrg 255539413783Smrg xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) { 255639413783Smrg drmmode_lease_private_ptr lease_private = lease->devPrivate; 255739413783Smrg 255839413783Smrg for (l = 0; l < lessees->count; l++) { 255939413783Smrg if (lessees->lessees[l] == lease_private->lessee_id) 256039413783Smrg break; 256139413783Smrg } 256239413783Smrg 256339413783Smrg /* check to see if the lease has gone away */ 256439413783Smrg if (l == lessees->count) { 256539413783Smrg free(lease_private); 256639413783Smrg lease->devPrivate = NULL; 256739413783Smrg xf86CrtcLeaseTerminated(lease); 256839413783Smrg } 256939413783Smrg } 257039413783Smrg 257139413783Smrg free(lessees); 257239413783Smrg#endif 257339413783Smrg} 257439413783Smrg 257539413783Smrg#ifdef XF86_LEASE_VERSION 257639413783Smrg 257739413783Smrgstatic int 257839413783Smrgdrmmode_create_lease(RRLeasePtr lease, int *fd) 257939413783Smrg{ 258039413783Smrg ScreenPtr screen = lease->screen; 258139413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 258239413783Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 258339413783Smrg drmmode_lease_private_ptr lease_private; 258439413783Smrg int noutput = lease->numOutputs; 258539413783Smrg int ncrtc = lease->numCrtcs; 258639413783Smrg uint32_t *objects; 258739413783Smrg size_t nobjects; 258839413783Smrg int lease_fd; 258939413783Smrg int c, o; 259039413783Smrg int i; 259139413783Smrg 259239413783Smrg nobjects = ncrtc + noutput; 259339413783Smrg if (nobjects == 0 || nobjects > (SIZE_MAX / 4) || 259439413783Smrg ncrtc > (SIZE_MAX - noutput)) 259539413783Smrg return BadValue; 259639413783Smrg 259739413783Smrg lease_private = calloc(1, sizeof (drmmode_lease_private_rec)); 259839413783Smrg if (!lease_private) 259939413783Smrg return BadAlloc; 260039413783Smrg 260139413783Smrg objects = malloc(nobjects * 4); 260239413783Smrg if (!objects) { 260339413783Smrg free(lease_private); 260439413783Smrg return BadAlloc; 260539413783Smrg } 260639413783Smrg 260739413783Smrg i = 0; 260839413783Smrg 260939413783Smrg /* Add CRTC ids */ 261039413783Smrg for (c = 0; c < ncrtc; c++) { 261139413783Smrg xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate; 261239413783Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 261339413783Smrg 261439413783Smrg objects[i++] = drmmode_crtc->mode_crtc->crtc_id; 261539413783Smrg } 261639413783Smrg 261739413783Smrg /* Add connector ids */ 261839413783Smrg for (o = 0; o < noutput; o++) { 261939413783Smrg xf86OutputPtr output = lease->outputs[o]->devPrivate; 262039413783Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 262139413783Smrg 262239413783Smrg objects[i++] = drmmode_output->mode_output->connector_id; 262339413783Smrg } 262439413783Smrg 262539413783Smrg /* call kernel to create lease */ 262639413783Smrg assert (i == nobjects); 262739413783Smrg 262839413783Smrg lease_fd = drmModeCreateLease(pRADEONEnt->fd, objects, nobjects, 0, 262939413783Smrg &lease_private->lessee_id); 263039413783Smrg 263139413783Smrg free(objects); 263239413783Smrg 263339413783Smrg if (lease_fd < 0) { 263439413783Smrg free(lease_private); 263539413783Smrg return BadMatch; 263639413783Smrg } 263739413783Smrg 263839413783Smrg lease->devPrivate = lease_private; 263939413783Smrg 264039413783Smrg xf86CrtcLeaseStarted(lease); 264139413783Smrg 264239413783Smrg *fd = lease_fd; 264339413783Smrg return Success; 264439413783Smrg} 264539413783Smrg 264639413783Smrgstatic void 264739413783Smrgdrmmode_terminate_lease(RRLeasePtr lease) 264839413783Smrg{ 264939413783Smrg drmmode_lease_private_ptr lease_private = lease->devPrivate; 265039413783Smrg ScreenPtr screen = lease->screen; 265139413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 265239413783Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 265339413783Smrg 265439413783Smrg if (drmModeRevokeLease(pRADEONEnt->fd, lease_private->lessee_id) == 0) { 265539413783Smrg free(lease_private); 265639413783Smrg lease->devPrivate = NULL; 265739413783Smrg xf86CrtcLeaseTerminated(lease); 265839413783Smrg } 265939413783Smrg} 266039413783Smrg 266139413783Smrg#endif // XF86_LEASE_VERSION 266239413783Smrg 2663de2362d3Smrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { 266439413783Smrg .resize = drmmode_xf86crtc_resize, 266539413783Smrg#ifdef XF86_LEASE_VERSION 266639413783Smrg .create_lease = drmmode_create_lease, 266739413783Smrg .terminate_lease = drmmode_terminate_lease 266839413783Smrg#endif 2669de2362d3Smrg}; 2670de2362d3Smrg 2671de2362d3Smrgstatic void 267218781e08Smrgdrmmode_flip_abort(xf86CrtcPtr crtc, void *event_data) 2673de2362d3Smrg{ 26748bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 26758bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 267618781e08Smrg drmmode_flipdata_ptr flipdata = event_data; 267739413783Smrg int crtc_id = drmmode_get_crtc_id(crtc); 267839413783Smrg struct drmmode_fb **fb = &flipdata->fb[crtc_id]; 267939413783Smrg 268039413783Smrg if (drmmode_crtc->flip_pending == *fb) { 268139413783Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->flip_pending, 268239413783Smrg NULL); 268339413783Smrg } 268439413783Smrg drmmode_fb_reference(pRADEONEnt->fd, fb, NULL); 268518781e08Smrg 268618781e08Smrg if (--flipdata->flip_count == 0) { 268718781e08Smrg if (!flipdata->fe_crtc) 268818781e08Smrg flipdata->fe_crtc = crtc; 268918781e08Smrg flipdata->abort(flipdata->fe_crtc, flipdata->event_data); 269018781e08Smrg free(flipdata); 269118781e08Smrg } 2692de2362d3Smrg} 2693de2362d3Smrg 2694de2362d3Smrgstatic void 269518781e08Smrgdrmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data) 2696de2362d3Smrg{ 26978bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 26988bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 269918781e08Smrg drmmode_flipdata_ptr flipdata = event_data; 270039413783Smrg int crtc_id = drmmode_get_crtc_id(crtc); 270139413783Smrg struct drmmode_fb **fb = &flipdata->fb[crtc_id]; 2702de2362d3Smrg 2703de2362d3Smrg /* Is this the event whose info shall be delivered to higher level? */ 270418781e08Smrg if (crtc == flipdata->fe_crtc) { 2705de2362d3Smrg /* Yes: Cache msc, ust for later delivery. */ 2706de2362d3Smrg flipdata->fe_frame = frame; 270718781e08Smrg flipdata->fe_usec = usec; 2708de2362d3Smrg } 2709de2362d3Smrg 2710446f62d6Smrg if (*fb) { 2711446f62d6Smrg if (drmmode_crtc->flip_pending == *fb) { 2712446f62d6Smrg drmmode_fb_reference(pRADEONEnt->fd, 2713446f62d6Smrg &drmmode_crtc->flip_pending, NULL); 2714446f62d6Smrg } 2715446f62d6Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, *fb); 2716446f62d6Smrg drmmode_fb_reference(pRADEONEnt->fd, fb, NULL); 27178bf5c682Smrg } 27188bf5c682Smrg 271918781e08Smrg if (--flipdata->flip_count == 0) { 272018781e08Smrg /* Deliver MSC & UST from reference/current CRTC to flip event 272118781e08Smrg * handler 272218781e08Smrg */ 272318781e08Smrg if (flipdata->fe_crtc) 272418781e08Smrg flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame, 272518781e08Smrg flipdata->fe_usec, flipdata->event_data); 272618781e08Smrg else 272718781e08Smrg flipdata->handler(crtc, frame, usec, flipdata->event_data); 2728de2362d3Smrg 272918781e08Smrg free(flipdata); 273018781e08Smrg } 2731de2362d3Smrg} 2732de2362d3Smrg 2733de2362d3Smrg 273418781e08Smrg#if HAVE_NOTIFY_FD 273518781e08Smrgstatic void 273618781e08Smrgdrm_notify_fd(int fd, int ready, void *data) 273718781e08Smrg#else 2738de2362d3Smrgstatic void 2739de2362d3Smrgdrm_wakeup_handler(pointer data, int err, pointer p) 274018781e08Smrg#endif 2741de2362d3Smrg{ 274239413783Smrg drmmode_ptr drmmode = data; 274339413783Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(drmmode->scrn); 27448bf5c682Smrg 274518781e08Smrg#if !HAVE_NOTIFY_FD 2746de2362d3Smrg fd_set *read_mask = p; 2747de2362d3Smrg 27488bf5c682Smrg if (err >= 0 && FD_ISSET(pRADEONEnt->fd, read_mask)) 274918781e08Smrg#endif 275018781e08Smrg { 275139413783Smrg radeon_drm_handle_event(pRADEONEnt->fd, &drmmode->event_context); 2752de2362d3Smrg } 2753de2362d3Smrg} 2754de2362d3Smrg 27558bf5c682Smrgstatic Bool drmmode_probe_page_flip_target(RADEONEntPtr pRADEONEnt) 27563ed65abbSmrg{ 27573ed65abbSmrg#ifdef DRM_CAP_PAGE_FLIP_TARGET 27583ed65abbSmrg uint64_t cap_value; 27593ed65abbSmrg 27608bf5c682Smrg return drmGetCap(pRADEONEnt->fd, DRM_CAP_PAGE_FLIP_TARGET, 27613ed65abbSmrg &cap_value) == 0 && cap_value != 0; 27623ed65abbSmrg#else 27633ed65abbSmrg return FALSE; 27643ed65abbSmrg#endif 27653ed65abbSmrg} 27663ed65abbSmrg 27673ed65abbSmrgstatic int 27688bf5c682Smrgdrmmode_page_flip(RADEONEntPtr pRADEONEnt, 27698bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc, int fb_id, 27703ed65abbSmrg uint32_t flags, uintptr_t drm_queue_seq) 27713ed65abbSmrg{ 27723ed65abbSmrg flags |= DRM_MODE_PAGE_FLIP_EVENT; 27738bf5c682Smrg return drmModePageFlip(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 27743ed65abbSmrg fb_id, flags, (void*)drm_queue_seq); 27753ed65abbSmrg} 27763ed65abbSmrg 27773ed65abbSmrgint 27783ed65abbSmrgdrmmode_page_flip_target_absolute(RADEONEntPtr pRADEONEnt, 27793ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc, 27803ed65abbSmrg int fb_id, uint32_t flags, 27813ed65abbSmrg uintptr_t drm_queue_seq, uint32_t target_msc) 27823ed65abbSmrg{ 27833ed65abbSmrg#ifdef DRM_MODE_PAGE_FLIP_TARGET 27843ed65abbSmrg if (pRADEONEnt->has_page_flip_target) { 27853ed65abbSmrg flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE; 27868bf5c682Smrg return drmModePageFlipTarget(pRADEONEnt->fd, 27873ed65abbSmrg drmmode_crtc->mode_crtc->crtc_id, 27883ed65abbSmrg fb_id, flags, (void*)drm_queue_seq, 27893ed65abbSmrg target_msc); 27903ed65abbSmrg } 27913ed65abbSmrg#endif 27923ed65abbSmrg 27938bf5c682Smrg return drmmode_page_flip(pRADEONEnt, drmmode_crtc, fb_id, flags, 27948bf5c682Smrg drm_queue_seq); 27953ed65abbSmrg} 27963ed65abbSmrg 27973ed65abbSmrgint 27983ed65abbSmrgdrmmode_page_flip_target_relative(RADEONEntPtr pRADEONEnt, 27993ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc, 28003ed65abbSmrg int fb_id, uint32_t flags, 28013ed65abbSmrg uintptr_t drm_queue_seq, uint32_t target_msc) 28023ed65abbSmrg{ 28033ed65abbSmrg#ifdef DRM_MODE_PAGE_FLIP_TARGET 28043ed65abbSmrg if (pRADEONEnt->has_page_flip_target) { 28053ed65abbSmrg flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE; 28068bf5c682Smrg return drmModePageFlipTarget(pRADEONEnt->fd, 28073ed65abbSmrg drmmode_crtc->mode_crtc->crtc_id, 28083ed65abbSmrg fb_id, flags, (void*)drm_queue_seq, 28093ed65abbSmrg target_msc); 28103ed65abbSmrg } 28113ed65abbSmrg#endif 28123ed65abbSmrg 28138bf5c682Smrg return drmmode_page_flip(pRADEONEnt, drmmode_crtc, fb_id, flags, 28148bf5c682Smrg drm_queue_seq); 28153ed65abbSmrg} 28163ed65abbSmrg 2817de2362d3SmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) 2818de2362d3Smrg{ 281918781e08Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 282018781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 2821de2362d3Smrg int i, num_dvi = 0, num_hdmi = 0; 282218781e08Smrg drmModeResPtr mode_res; 282318781e08Smrg unsigned int crtcs_needed = 0; 2824446f62d6Smrg unsigned int crtcs_got = 0; 282518781e08Smrg char *bus_id_string, *provider_name; 2826de2362d3Smrg 2827de2362d3Smrg xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); 2828de2362d3Smrg 2829de2362d3Smrg drmmode->scrn = pScrn; 28308bf5c682Smrg mode_res = drmModeGetResources(pRADEONEnt->fd); 283118781e08Smrg if (!mode_res) 2832de2362d3Smrg return FALSE; 2833de2362d3Smrg 283418781e08Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 283518781e08Smrg "Initializing outputs ...\n"); 283618781e08Smrg for (i = 0; i < mode_res->count_connectors; i++) 283718781e08Smrg crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, 283818781e08Smrg i, &num_dvi, &num_hdmi, 0); 283918781e08Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 284018781e08Smrg "%d crtcs needed for screen.\n", crtcs_needed); 284118781e08Smrg 28428bf5c682Smrg /* Need per-screen drmmode_crtc_funcs, based on our global template, 28438bf5c682Smrg * so we can disable some functions, depending on screen settings. 28448bf5c682Smrg */ 28458bf5c682Smrg info->drmmode_crtc_funcs = drmmode_crtc_funcs; 28468bf5c682Smrg 284718781e08Smrg if (info->r600_shadow_fb) { 284818781e08Smrg /* Rotation requires hardware acceleration */ 28498bf5c682Smrg info->drmmode_crtc_funcs.shadow_allocate = NULL; 28508bf5c682Smrg info->drmmode_crtc_funcs.shadow_create = NULL; 28518bf5c682Smrg info->drmmode_crtc_funcs.shadow_destroy = NULL; 285218781e08Smrg } 285318781e08Smrg 28548bf5c682Smrg /* Hw gamma lut's are currently bypassed by the hw at color depth 30, 28558bf5c682Smrg * so spare the server the effort to compute and update the cluts. 28568bf5c682Smrg */ 28578bf5c682Smrg if (pScrn->depth == 30) 28588bf5c682Smrg info->drmmode_crtc_funcs.gamma_set = NULL; 28598bf5c682Smrg 286018781e08Smrg drmmode->count_crtcs = mode_res->count_crtcs; 286118781e08Smrg xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, mode_res->max_height); 286218781e08Smrg 2863446f62d6Smrg for (i = 0; i < mode_res->count_crtcs; i++) { 286418781e08Smrg if (!xf86IsEntityShared(pScrn->entityList[0]) || 2865446f62d6Smrg (crtcs_got < crtcs_needed && 2866446f62d6Smrg !(pRADEONEnt->assigned_crtcs & (1 << i)))) 2867446f62d6Smrg crtcs_got += drmmode_crtc_init(pScrn, drmmode, mode_res, i); 2868446f62d6Smrg } 2869de2362d3Smrg 287018781e08Smrg /* All ZaphodHeads outputs provided with matching crtcs? */ 2871446f62d6Smrg if (crtcs_got < crtcs_needed) { 2872446f62d6Smrg if (crtcs_got == 0) { 2873446f62d6Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 2874446f62d6Smrg "No ZaphodHeads CRTC available, needed %u\n", 2875446f62d6Smrg crtcs_needed); 2876446f62d6Smrg return FALSE; 2877446f62d6Smrg } 2878446f62d6Smrg 287918781e08Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 288018781e08Smrg "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n", 288118781e08Smrg crtcs_needed); 2882446f62d6Smrg } 2883de2362d3Smrg 2884de2362d3Smrg /* workout clones */ 288518781e08Smrg drmmode_clones_init(pScrn, drmmode, mode_res); 288618781e08Smrg 288718781e08Smrg bus_id_string = DRICreatePCIBusID(info->PciInfo); 288818781e08Smrg XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, bus_id_string); 288918781e08Smrg free(bus_id_string); 289018781e08Smrg xf86ProviderSetup(pScrn, NULL, provider_name); 289118781e08Smrg free(provider_name); 2892de2362d3Smrg 2893de2362d3Smrg xf86InitialConfiguration(pScrn, TRUE); 2894de2362d3Smrg 28958bf5c682Smrg pRADEONEnt->has_page_flip_target = drmmode_probe_page_flip_target(pRADEONEnt); 28963ed65abbSmrg 289718781e08Smrg drmModeFreeResources(mode_res); 2898de2362d3Smrg return TRUE; 2899de2362d3Smrg} 2900de2362d3Smrg 2901de2362d3Smrgvoid drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 2902de2362d3Smrg{ 2903de2362d3Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 2904de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 2905de2362d3Smrg 290618781e08Smrg if (info->dri2.pKernelDRMVersion->version_minor < 4) 290718781e08Smrg return; 290818781e08Smrg 290918781e08Smrg info->drmmode_inited = TRUE; 291018781e08Smrg if (pRADEONEnt->fd_wakeup_registered != serverGeneration) { 291118781e08Smrg#if HAVE_NOTIFY_FD 291239413783Smrg SetNotifyFd(pRADEONEnt->fd, drm_notify_fd, X_NOTIFY_READ, 291339413783Smrg &info->drmmode); 291418781e08Smrg#else 29158bf5c682Smrg AddGeneralSocket(pRADEONEnt->fd); 2916de2362d3Smrg RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, 291739413783Smrg drm_wakeup_handler, 291839413783Smrg &info->drmmode); 291918781e08Smrg#endif 2920de2362d3Smrg pRADEONEnt->fd_wakeup_registered = serverGeneration; 292118781e08Smrg pRADEONEnt->fd_wakeup_ref = 1; 292218781e08Smrg } else 292318781e08Smrg pRADEONEnt->fd_wakeup_ref++; 292418781e08Smrg} 292518781e08Smrg 292618781e08Smrgvoid drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 292718781e08Smrg{ 292818781e08Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 292918781e08Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 293018781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 293118781e08Smrg int c; 293218781e08Smrg 293318781e08Smrg if (info->dri2.pKernelDRMVersion->version_minor < 4 || !info->drmmode_inited) 293418781e08Smrg return; 293518781e08Smrg 2936446f62d6Smrg for (c = 0; c < config->num_crtc; c++) 2937446f62d6Smrg drmmode_crtc_scanout_free(config->crtc[c]); 2938446f62d6Smrg 293918781e08Smrg if (pRADEONEnt->fd_wakeup_registered == serverGeneration && 294018781e08Smrg !--pRADEONEnt->fd_wakeup_ref) { 294118781e08Smrg#if HAVE_NOTIFY_FD 29428bf5c682Smrg RemoveNotifyFd(pRADEONEnt->fd); 294318781e08Smrg#else 29448bf5c682Smrg RemoveGeneralSocket(pRADEONEnt->fd); 294518781e08Smrg RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, 29468bf5c682Smrg drm_wakeup_handler, pScrn); 294718781e08Smrg#endif 294818781e08Smrg } 2949de2362d3Smrg} 2950de2362d3Smrg 295118781e08Smrg 2952de2362d3SmrgBool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, struct radeon_bo_manager *bufmgr) 2953de2362d3Smrg{ 2954de2362d3Smrg drmmode->bufmgr = bufmgr; 2955de2362d3Smrg return TRUE; 2956de2362d3Smrg} 2957de2362d3Smrg 2958de2362d3Smrg 29598bf5c682Smrgstatic void drmmode_sprite_do_set_cursor(struct radeon_device_priv *device_priv, 29608bf5c682Smrg ScrnInfoPtr scrn, int x, int y) 29618bf5c682Smrg{ 29628bf5c682Smrg RADEONInfoPtr info = RADEONPTR(scrn); 29638bf5c682Smrg CursorPtr cursor = device_priv->cursor; 29648bf5c682Smrg Bool sprite_visible = device_priv->sprite_visible; 29658bf5c682Smrg 29668bf5c682Smrg if (cursor) { 29678bf5c682Smrg x -= cursor->bits->xhot; 29688bf5c682Smrg y -= cursor->bits->yhot; 29698bf5c682Smrg 29708bf5c682Smrg device_priv->sprite_visible = 29718bf5c682Smrg x < scrn->virtualX && y < scrn->virtualY && 29728bf5c682Smrg (x + cursor->bits->width > 0) && 29738bf5c682Smrg (y + cursor->bits->height > 0); 29748bf5c682Smrg } else { 29758bf5c682Smrg device_priv->sprite_visible = FALSE; 29768bf5c682Smrg } 29778bf5c682Smrg 29788bf5c682Smrg info->sprites_visible += device_priv->sprite_visible - sprite_visible; 29798bf5c682Smrg} 29808bf5c682Smrg 298139413783Smrgstatic void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 298239413783Smrg CursorPtr pCursor, int x, int y) 29838bf5c682Smrg{ 29848bf5c682Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 29858bf5c682Smrg RADEONInfoPtr info = RADEONPTR(scrn); 29868bf5c682Smrg struct radeon_device_priv *device_priv = 29878bf5c682Smrg dixLookupScreenPrivate(&pDev->devPrivates, 29888bf5c682Smrg &radeon_device_private_key, pScreen); 29898bf5c682Smrg 29908bf5c682Smrg device_priv->cursor = pCursor; 29918bf5c682Smrg drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 29928bf5c682Smrg 299339413783Smrg info->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y); 29948bf5c682Smrg} 29958bf5c682Smrg 299639413783Smrgstatic void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 299739413783Smrg int x, int y) 29988bf5c682Smrg{ 29998bf5c682Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 30008bf5c682Smrg RADEONInfoPtr info = RADEONPTR(scrn); 30018bf5c682Smrg struct radeon_device_priv *device_priv = 30028bf5c682Smrg dixLookupScreenPrivate(&pDev->devPrivates, 30038bf5c682Smrg &radeon_device_private_key, pScreen); 30048bf5c682Smrg 30058bf5c682Smrg drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 30068bf5c682Smrg 300739413783Smrg info->SpriteFuncs->MoveCursor(pDev, pScreen, x, y); 300839413783Smrg} 300939413783Smrg 301039413783Smrgstatic Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev, 301139413783Smrg ScreenPtr pScreen, 301239413783Smrg CursorPtr pCursor) 301339413783Smrg{ 301439413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 301539413783Smrg RADEONInfoPtr info = RADEONPTR(scrn); 301639413783Smrg 301739413783Smrg return info->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor); 301839413783Smrg} 301939413783Smrg 302039413783Smrgstatic Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev, 302139413783Smrg ScreenPtr pScreen, 302239413783Smrg CursorPtr pCursor) 302339413783Smrg{ 302439413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 302539413783Smrg RADEONInfoPtr info = RADEONPTR(scrn); 302639413783Smrg 302739413783Smrg return info->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor); 302839413783Smrg} 302939413783Smrg 303039413783Smrgstatic Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev, 303139413783Smrg ScreenPtr pScreen) 303239413783Smrg{ 303339413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 303439413783Smrg RADEONInfoPtr info = RADEONPTR(scrn); 303539413783Smrg 303639413783Smrg return info->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen); 30378bf5c682Smrg} 3038de2362d3Smrg 303939413783Smrgstatic void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev, 304039413783Smrg ScreenPtr pScreen) 304139413783Smrg{ 304239413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 304339413783Smrg RADEONInfoPtr info = RADEONPTR(scrn); 304439413783Smrg 304539413783Smrg info->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen); 304639413783Smrg} 304739413783Smrg 304839413783SmrgmiPointerSpriteFuncRec drmmode_sprite_funcs = { 304939413783Smrg .RealizeCursor = drmmode_sprite_realize_realize_cursor, 305039413783Smrg .UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor, 305139413783Smrg .SetCursor = drmmode_sprite_set_cursor, 305239413783Smrg .MoveCursor = drmmode_sprite_move_cursor, 305339413783Smrg .DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize, 305439413783Smrg .DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup, 305539413783Smrg}; 305639413783Smrg 305739413783Smrg 3058de2362d3Smrgvoid drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y) 3059de2362d3Smrg{ 3060de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 3061de2362d3Smrg xf86OutputPtr output = config->output[config->compat_output]; 3062de2362d3Smrg xf86CrtcPtr crtc = output->crtc; 3063de2362d3Smrg 3064de2362d3Smrg if (crtc && crtc->enabled) { 3065de2362d3Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 3066de2362d3Smrg x, y); 3067de2362d3Smrg } 3068de2362d3Smrg} 3069de2362d3Smrg 307018781e08SmrgBool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, 307118781e08Smrg Bool set_hw) 3072de2362d3Smrg{ 3073de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 30748bf5c682Smrg unsigned num_desired = 0, num_on = 0; 3075de2362d3Smrg int c; 3076de2362d3Smrg 30778bf5c682Smrg /* First, disable all unused CRTCs */ 30788bf5c682Smrg if (set_hw) { 30798bf5c682Smrg for (c = 0; c < config->num_crtc; c++) { 30808bf5c682Smrg xf86CrtcPtr crtc = config->crtc[c]; 30818bf5c682Smrg 30828bf5c682Smrg /* Skip disabled CRTCs */ 30838bf5c682Smrg if (crtc->enabled) 30848bf5c682Smrg continue; 30858bf5c682Smrg 308639413783Smrg drmmode_crtc_dpms(crtc, DPMSModeOff); 30878bf5c682Smrg } 30888bf5c682Smrg } 30898bf5c682Smrg 30908bf5c682Smrg /* Then, try setting the chosen mode on each CRTC */ 3091de2362d3Smrg for (c = 0; c < config->num_crtc; c++) { 3092de2362d3Smrg xf86CrtcPtr crtc = config->crtc[c]; 3093de2362d3Smrg xf86OutputPtr output = NULL; 3094de2362d3Smrg int o; 3095de2362d3Smrg 30968bf5c682Smrg if (!crtc->enabled) 3097de2362d3Smrg continue; 3098de2362d3Smrg 3099de2362d3Smrg if (config->output[config->compat_output]->crtc == crtc) 3100de2362d3Smrg output = config->output[config->compat_output]; 3101de2362d3Smrg else 3102de2362d3Smrg { 3103de2362d3Smrg for (o = 0; o < config->num_output; o++) 3104de2362d3Smrg if (config->output[o]->crtc == crtc) 3105de2362d3Smrg { 3106de2362d3Smrg output = config->output[o]; 3107de2362d3Smrg break; 3108de2362d3Smrg } 3109de2362d3Smrg } 3110de2362d3Smrg /* paranoia */ 3111de2362d3Smrg if (!output) 3112de2362d3Smrg continue; 3113de2362d3Smrg 31148bf5c682Smrg num_desired++; 31158bf5c682Smrg 3116de2362d3Smrg /* Mark that we'll need to re-set the mode for sure */ 3117de2362d3Smrg memset(&crtc->mode, 0, sizeof(crtc->mode)); 3118de2362d3Smrg if (!crtc->desiredMode.CrtcHDisplay) 3119de2362d3Smrg { 3120de2362d3Smrg DisplayModePtr mode = xf86OutputFindClosestMode (output, pScrn->currentMode); 3121de2362d3Smrg 31228bf5c682Smrg if (!mode) { 31238bf5c682Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 31248bf5c682Smrg "Failed to find mode for CRTC %d\n", c); 31258bf5c682Smrg continue; 31268bf5c682Smrg } 3127de2362d3Smrg crtc->desiredMode = *mode; 3128de2362d3Smrg crtc->desiredRotation = RR_Rotate_0; 3129de2362d3Smrg crtc->desiredX = 0; 3130de2362d3Smrg crtc->desiredY = 0; 3131de2362d3Smrg } 3132de2362d3Smrg 313318781e08Smrg if (set_hw) { 31348bf5c682Smrg if (crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, 31358bf5c682Smrg crtc->desiredRotation, 31368bf5c682Smrg crtc->desiredX, 31378bf5c682Smrg crtc->desiredY)) { 31388bf5c682Smrg num_on++; 31398bf5c682Smrg } else { 31408bf5c682Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 31418bf5c682Smrg "Failed to set mode on CRTC %d\n", c); 314239413783Smrg RRCrtcSet(crtc->randr_crtc, NULL, crtc->x, crtc->y, 314339413783Smrg crtc->rotation, 0, NULL); 31448bf5c682Smrg } 314518781e08Smrg } else { 314618781e08Smrg crtc->mode = crtc->desiredMode; 314718781e08Smrg crtc->rotation = crtc->desiredRotation; 314818781e08Smrg crtc->x = crtc->desiredX; 314918781e08Smrg crtc->y = crtc->desiredY; 31508bf5c682Smrg if (drmmode_handle_transform(crtc)) 31518bf5c682Smrg num_on++; 315218781e08Smrg } 3153de2362d3Smrg } 31548bf5c682Smrg 31558bf5c682Smrg if (num_on == 0 && num_desired > 0) { 31568bf5c682Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to enable any CRTC\n"); 31578bf5c682Smrg return FALSE; 31588bf5c682Smrg } 31598bf5c682Smrg 316039413783Smrg /* Validate leases on VT re-entry */ 3161446f62d6Smrg if (dixPrivateKeyRegistered(rrPrivKey)) 3162446f62d6Smrg drmmode_validate_leases(pScrn); 316339413783Smrg 3164de2362d3Smrg return TRUE; 3165de2362d3Smrg} 3166de2362d3Smrg 316718781e08SmrgBool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn) 3168de2362d3Smrg{ 3169de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 317039413783Smrg int i; 3171de2362d3Smrg 317218781e08Smrg if (xf86_config->num_crtc) { 317318781e08Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 317418781e08Smrg "Initializing kms color map\n"); 317518781e08Smrg if (!miCreateDefColormap(pScreen)) 317618781e08Smrg return FALSE; 31778bf5c682Smrg 31788bf5c682Smrg /* All radeons support 10 bit CLUTs. They get bypassed at depth 30. */ 317939413783Smrg if (pScrn->depth != 30) { 318039413783Smrg if (!xf86HandleColormaps(pScreen, 256, 10, NULL, NULL, 318139413783Smrg CMAP_PALETTED_TRUECOLOR 318239413783Smrg | CMAP_RELOAD_ON_MODE_SWITCH)) 318339413783Smrg return FALSE; 318439413783Smrg 318539413783Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 318639413783Smrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 318739413783Smrg 318839413783Smrg drmmode_crtc_gamma_do_set(crtc, crtc->gamma_red, 318939413783Smrg crtc->gamma_green, 319039413783Smrg crtc->gamma_blue, 319139413783Smrg crtc->gamma_size); 319239413783Smrg } 319339413783Smrg } 319418781e08Smrg } 319539413783Smrg 319618781e08Smrg return TRUE; 319718781e08Smrg} 31987314432eSmrg 319918781e08Smrgstatic Bool 320018781e08Smrgdrmmode_find_output(ScrnInfoPtr scrn, int output_id, int *num_dvi, 320118781e08Smrg int *num_hdmi) 320218781e08Smrg{ 320318781e08Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 320418781e08Smrg int i; 32057314432eSmrg 320618781e08Smrg for (i = 0; i < config->num_output; i++) { 320718781e08Smrg xf86OutputPtr output = config->output[i]; 320818781e08Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 320918781e08Smrg 321018781e08Smrg if (drmmode_output->output_id == output_id) { 321118781e08Smrg switch(drmmode_output->mode_output->connector_type) { 321218781e08Smrg case DRM_MODE_CONNECTOR_DVII: 321318781e08Smrg case DRM_MODE_CONNECTOR_DVID: 321418781e08Smrg case DRM_MODE_CONNECTOR_DVIA: 321518781e08Smrg (*num_dvi)++; 321618781e08Smrg break; 321718781e08Smrg case DRM_MODE_CONNECTOR_HDMIA: 321818781e08Smrg case DRM_MODE_CONNECTOR_HDMIB: 321918781e08Smrg (*num_hdmi)++; 322018781e08Smrg break; 322118781e08Smrg } 322218781e08Smrg 322318781e08Smrg return TRUE; 322418781e08Smrg } 322518781e08Smrg } 322618781e08Smrg 322718781e08Smrg return FALSE; 32287314432eSmrg} 32297314432eSmrg 323018781e08Smrgvoid 323118781e08Smrgradeon_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode) 32320d16fef4Smrg{ 323318781e08Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 323418781e08Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 323518781e08Smrg drmModeResPtr mode_res; 323618781e08Smrg int i, j; 323718781e08Smrg Bool found; 323818781e08Smrg Bool changed = FALSE; 323918781e08Smrg int num_dvi = 0, num_hdmi = 0; 324018781e08Smrg 32418bf5c682Smrg /* Try to re-set the mode on all the connectors with a BAD link-state: 32428bf5c682Smrg * This may happen if a link degrades and a new modeset is necessary, using 32438bf5c682Smrg * different link-training parameters. If the kernel found that the current 32448bf5c682Smrg * mode is not achievable anymore, it should have pruned the mode before 32458bf5c682Smrg * sending the hotplug event. Try to re-set the currently-set mode to keep 32468bf5c682Smrg * the display alive, this will fail if the mode has been pruned. 32478bf5c682Smrg * In any case, we will send randr events for the Desktop Environment to 32488bf5c682Smrg * deal with it, if it wants to. 32498bf5c682Smrg */ 32508bf5c682Smrg for (i = 0; i < config->num_output; i++) { 32518bf5c682Smrg xf86OutputPtr output = config->output[i]; 32528bf5c682Smrg xf86CrtcPtr crtc = output->crtc; 32538bf5c682Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 32548bf5c682Smrg 32558bf5c682Smrg drmmode_output_detect(output); 32568bf5c682Smrg 32578bf5c682Smrg if (!crtc || !drmmode_output->mode_output) 32588bf5c682Smrg continue; 32598bf5c682Smrg 32608bf5c682Smrg /* Get an updated view of the properties for the current connector and 32618bf5c682Smrg * look for the link-status property 32628bf5c682Smrg */ 32638bf5c682Smrg for (j = 0; j < drmmode_output->num_props; j++) { 32648bf5c682Smrg drmmode_prop_ptr p = &drmmode_output->props[j]; 32658bf5c682Smrg 32668bf5c682Smrg if (!strcmp(p->mode_prop->name, "link-status")) { 32678bf5c682Smrg if (p->value != DRM_MODE_LINK_STATUS_BAD) 32688bf5c682Smrg break; 32698bf5c682Smrg 32708bf5c682Smrg /* the connector got a link failure, re-set the current mode */ 32718bf5c682Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 32728bf5c682Smrg crtc->x, crtc->y); 32738bf5c682Smrg 32748bf5c682Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 32758bf5c682Smrg "hotplug event: connector %u's link-state is BAD, " 32768bf5c682Smrg "tried resetting the current mode. You may be left" 32778bf5c682Smrg "with a black screen if this fails...\n", 32788bf5c682Smrg drmmode_output->mode_output->connector_id); 32798bf5c682Smrg 32808bf5c682Smrg break; 32818bf5c682Smrg } 32828bf5c682Smrg } 32838bf5c682Smrg } 32848bf5c682Smrg 32858bf5c682Smrg mode_res = drmModeGetResources(pRADEONEnt->fd); 328618781e08Smrg if (!mode_res) 328718781e08Smrg goto out; 328818781e08Smrg 328918781e08Smrgrestart_destroy: 329018781e08Smrg for (i = 0; i < config->num_output; i++) { 329118781e08Smrg xf86OutputPtr output = config->output[i]; 329218781e08Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 329318781e08Smrg found = FALSE; 329418781e08Smrg for (j = 0; j < mode_res->count_connectors; j++) { 329518781e08Smrg if (mode_res->connectors[j] == drmmode_output->output_id) { 329618781e08Smrg found = TRUE; 329718781e08Smrg break; 329818781e08Smrg } 329918781e08Smrg } 330018781e08Smrg if (found) 330118781e08Smrg continue; 330218781e08Smrg 330318781e08Smrg drmModeFreeConnector(drmmode_output->mode_output); 330418781e08Smrg drmmode_output->mode_output = NULL; 330518781e08Smrg drmmode_output->output_id = -1; 330618781e08Smrg 330718781e08Smrg changed = TRUE; 330818781e08Smrg if (drmmode->delete_dp_12_displays) { 330918781e08Smrg RROutputDestroy(output->randr_output); 331018781e08Smrg xf86OutputDestroy(output); 331118781e08Smrg goto restart_destroy; 331218781e08Smrg } 331318781e08Smrg } 331418781e08Smrg 331518781e08Smrg /* find new output ids we don't have outputs for */ 331618781e08Smrg for (i = 0; i < mode_res->count_connectors; i++) { 3317446f62d6Smrg for (j = 0; j < pRADEONEnt->num_scrns; j++) { 3318446f62d6Smrg if (drmmode_find_output(pRADEONEnt->scrn[j], 3319446f62d6Smrg mode_res->connectors[i], 3320446f62d6Smrg &num_dvi, &num_hdmi)) 3321446f62d6Smrg break; 3322446f62d6Smrg } 3323446f62d6Smrg 3324446f62d6Smrg if (j < pRADEONEnt->num_scrns) 332518781e08Smrg continue; 332618781e08Smrg 332718781e08Smrg if (drmmode_output_init(scrn, drmmode, mode_res, i, &num_dvi, 332818781e08Smrg &num_hdmi, 1) != 0) 332918781e08Smrg changed = TRUE; 333018781e08Smrg } 333118781e08Smrg 333239413783Smrg /* Check to see if a lessee has disappeared */ 333339413783Smrg drmmode_validate_leases(scrn); 333439413783Smrg 3335446f62d6Smrg if (changed) { 333618781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0) 333718781e08Smrg RRSetChanged(xf86ScrnToScreen(scrn)); 333818781e08Smrg#else 333918781e08Smrg rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen); 334018781e08Smrg rrScrPriv->changed = TRUE; 33410d16fef4Smrg#endif 334218781e08Smrg RRTellChanged(xf86ScrnToScreen(scrn)); 334318781e08Smrg } 33447821949aSmrg 334518781e08Smrg drmModeFreeResources(mode_res); 334618781e08Smrgout: 334718781e08Smrg RRGetInfo(xf86ScrnToScreen(scrn), TRUE); 334818781e08Smrg} 3349de2362d3Smrg#ifdef HAVE_LIBUDEV 3350de2362d3Smrgstatic void 3351de2362d3Smrgdrmmode_handle_uevents(int fd, void *closure) 3352de2362d3Smrg{ 3353de2362d3Smrg drmmode_ptr drmmode = closure; 3354de2362d3Smrg ScrnInfoPtr scrn = drmmode->scrn; 3355de2362d3Smrg struct udev_device *dev; 335618781e08Smrg Bool received = FALSE; 33573ed65abbSmrg struct timeval tv = { 0, 0 }; 33583ed65abbSmrg fd_set readfd; 33593ed65abbSmrg 33603ed65abbSmrg FD_ZERO(&readfd); 33613ed65abbSmrg FD_SET(fd, &readfd); 33623ed65abbSmrg 33633ed65abbSmrg while (select(fd + 1, &readfd, NULL, NULL, &tv) > 0 && 33643ed65abbSmrg FD_ISSET(fd, &readfd)) { 33653ed65abbSmrg /* select() ensured that this will not block */ 33663ed65abbSmrg dev = udev_monitor_receive_device(drmmode->uevent_monitor); 33673ed65abbSmrg if (dev) { 33683ed65abbSmrg udev_device_unref(dev); 33693ed65abbSmrg received = TRUE; 33703ed65abbSmrg } 337118781e08Smrg } 337218781e08Smrg 337318781e08Smrg if (received) 337418781e08Smrg radeon_mode_hotplug(scrn, drmmode); 3375de2362d3Smrg} 3376de2362d3Smrg#endif 3377de2362d3Smrg 3378de2362d3Smrgvoid drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3379de2362d3Smrg{ 3380de2362d3Smrg#ifdef HAVE_LIBUDEV 3381de2362d3Smrg struct udev *u; 3382de2362d3Smrg struct udev_monitor *mon; 3383de2362d3Smrg 3384de2362d3Smrg u = udev_new(); 3385de2362d3Smrg if (!u) 3386de2362d3Smrg return; 3387de2362d3Smrg mon = udev_monitor_new_from_netlink(u, "udev"); 3388de2362d3Smrg if (!mon) { 3389de2362d3Smrg udev_unref(u); 3390de2362d3Smrg return; 3391de2362d3Smrg } 3392de2362d3Smrg 3393de2362d3Smrg if (udev_monitor_filter_add_match_subsystem_devtype(mon, 3394de2362d3Smrg "drm", 3395de2362d3Smrg "drm_minor") < 0 || 3396de2362d3Smrg udev_monitor_enable_receiving(mon) < 0) { 3397de2362d3Smrg udev_monitor_unref(mon); 3398de2362d3Smrg udev_unref(u); 3399de2362d3Smrg return; 3400de2362d3Smrg } 3401de2362d3Smrg 3402de2362d3Smrg drmmode->uevent_handler = 3403de2362d3Smrg xf86AddGeneralHandler(udev_monitor_get_fd(mon), 3404de2362d3Smrg drmmode_handle_uevents, 3405de2362d3Smrg drmmode); 3406de2362d3Smrg 3407de2362d3Smrg drmmode->uevent_monitor = mon; 3408de2362d3Smrg#endif 3409de2362d3Smrg} 3410de2362d3Smrg 3411de2362d3Smrgvoid drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3412de2362d3Smrg{ 3413de2362d3Smrg#ifdef HAVE_LIBUDEV 3414de2362d3Smrg if (drmmode->uevent_handler) { 3415de2362d3Smrg struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); 3416de2362d3Smrg xf86RemoveGeneralHandler(drmmode->uevent_handler); 3417de2362d3Smrg 3418de2362d3Smrg udev_monitor_unref(drmmode->uevent_monitor); 3419de2362d3Smrg udev_unref(u); 3420de2362d3Smrg } 3421de2362d3Smrg#endif 3422de2362d3Smrg} 3423de2362d3Smrg 342418781e08SmrgBool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, 34258bf5c682Smrg PixmapPtr new_front, uint64_t id, void *data, 34268bf5c682Smrg xf86CrtcPtr ref_crtc, radeon_drm_handler_proc handler, 342718781e08Smrg radeon_drm_abort_proc abort, 34283ed65abbSmrg enum drmmode_flip_sync flip_sync, 34293ed65abbSmrg uint32_t target_msc) 3430de2362d3Smrg{ 34313ed65abbSmrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 3432de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 343318781e08Smrg xf86CrtcPtr crtc = NULL; 3434de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; 3435446f62d6Smrg int crtc_id; 34363ed65abbSmrg uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0; 3437de2362d3Smrg drmmode_flipdata_ptr flipdata; 343839413783Smrg Bool handle_deferred = FALSE; 343918781e08Smrg uintptr_t drm_queue_seq = 0; 344039413783Smrg struct drmmode_fb *fb; 344139413783Smrg int i = 0; 3442de2362d3Smrg 3443446f62d6Smrg flipdata = calloc(1, sizeof(*flipdata) + drmmode_crtc->drmmode->count_crtcs * 344439413783Smrg sizeof(flipdata->fb[0])); 34457821949aSmrg if (!flipdata) { 34467821949aSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 34477821949aSmrg "flip queue: data alloc failed.\n"); 344818781e08Smrg goto error; 34497821949aSmrg } 345018781e08Smrg 345139413783Smrg fb = radeon_pixmap_get_fb(new_front); 345239413783Smrg if (!fb) { 34538bf5c682Smrg ErrorF("Failed to get FB for flip\n"); 345418781e08Smrg goto error; 34558bf5c682Smrg } 345618781e08Smrg 3457de2362d3Smrg /* 3458de2362d3Smrg * Queue flips on all enabled CRTCs 3459de2362d3Smrg * Note that if/when we get per-CRTC buffers, we'll have to update this. 3460de2362d3Smrg * Right now it assumes a single shared fb across all CRTCs, with the 3461de2362d3Smrg * kernel fixing up the offset of each CRTC as necessary. 3462de2362d3Smrg * 3463de2362d3Smrg * Also, flips queued on disabled or incorrectly configured displays 3464de2362d3Smrg * may never complete; this is a configuration error. 3465de2362d3Smrg */ 3466de2362d3Smrg 3467de2362d3Smrg flipdata->event_data = data; 346818781e08Smrg flipdata->handler = handler; 346918781e08Smrg flipdata->abort = abort; 34708bf5c682Smrg flipdata->fe_crtc = ref_crtc; 347118781e08Smrg 3472de2362d3Smrg for (i = 0; i < config->num_crtc; i++) { 347318781e08Smrg crtc = config->crtc[i]; 34748bf5c682Smrg drmmode_crtc = crtc->driver_private; 3475446f62d6Smrg crtc_id = drmmode_get_crtc_id(crtc); 347618781e08Smrg 34778bf5c682Smrg if (!drmmode_crtc_can_flip(crtc) || 34788bf5c682Smrg (drmmode_crtc->tear_free && crtc != ref_crtc)) 3479de2362d3Smrg continue; 3480de2362d3Smrg 3481de2362d3Smrg flipdata->flip_count++; 348218781e08Smrg 348318781e08Smrg drm_queue_seq = radeon_drm_queue_alloc(crtc, client, id, 348418781e08Smrg flipdata, 348518781e08Smrg drmmode_flip_handler, 3486446f62d6Smrg drmmode_flip_abort, 3487446f62d6Smrg TRUE); 348818781e08Smrg if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { 348918781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 349018781e08Smrg "Allocating DRM queue event entry failed.\n"); 349118781e08Smrg goto error; 349218781e08Smrg } 3493de2362d3Smrg 34948bf5c682Smrg if (drmmode_crtc->tear_free) { 34958bf5c682Smrg BoxRec extents = { .x1 = 0, .y1 = 0, 34968bf5c682Smrg .x2 = new_front->drawable.width, 34978bf5c682Smrg .y2 = new_front->drawable.height }; 34988bf5c682Smrg int scanout_id = drmmode_crtc->scanout_id ^ 1; 34998bf5c682Smrg 35008bf5c682Smrg if (flip_sync == FLIP_ASYNC) { 35018bf5c682Smrg if (!drmmode_wait_vblank(crtc, 35028bf5c682Smrg DRM_VBLANK_RELATIVE | 35038bf5c682Smrg DRM_VBLANK_EVENT, 35048bf5c682Smrg 0, drm_queue_seq, 35058bf5c682Smrg NULL, NULL)) 35068bf5c682Smrg goto flip_error; 35078bf5c682Smrg goto next; 35088bf5c682Smrg } 35098bf5c682Smrg 3510446f62d6Smrg drmmode_fb_reference(pRADEONEnt->fd, &flipdata->fb[crtc_id], 351139413783Smrg radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap)); 3512446f62d6Smrg if (!flipdata->fb[crtc_id]) { 35138bf5c682Smrg ErrorF("Failed to get FB for TearFree flip\n"); 35148bf5c682Smrg goto error; 35158bf5c682Smrg } 35168bf5c682Smrg 35178bf5c682Smrg radeon_scanout_do_update(crtc, scanout_id, new_front, 351839413783Smrg extents); 351939413783Smrg radeon_cs_flush_indirect(crtc->scrn); 352039413783Smrg 352139413783Smrg if (drmmode_crtc->scanout_update_pending) { 352239413783Smrg radeon_drm_wait_pending_flip(crtc); 352339413783Smrg handle_deferred = TRUE; 352439413783Smrg radeon_drm_abort_entry(drmmode_crtc->scanout_update_pending); 352539413783Smrg drmmode_crtc->scanout_update_pending = 0; 352639413783Smrg } 352739413783Smrg } else { 3528446f62d6Smrg drmmode_fb_reference(pRADEONEnt->fd, &flipdata->fb[crtc_id], fb); 35298bf5c682Smrg } 35308bf5c682Smrg 35318bf5c682Smrg if (crtc == ref_crtc) { 35323ed65abbSmrg if (drmmode_page_flip_target_absolute(pRADEONEnt, 35333ed65abbSmrg drmmode_crtc, 3534446f62d6Smrg flipdata->fb[crtc_id]->handle, 35353ed65abbSmrg flip_flags, 35363ed65abbSmrg drm_queue_seq, 35373ed65abbSmrg target_msc) != 0) 35383ed65abbSmrg goto flip_error; 35393ed65abbSmrg } else { 35403ed65abbSmrg if (drmmode_page_flip_target_relative(pRADEONEnt, 35413ed65abbSmrg drmmode_crtc, 3542446f62d6Smrg flipdata->fb[crtc_id]->handle, 35433ed65abbSmrg flip_flags, 35443ed65abbSmrg drm_queue_seq, 0) != 0) 35453ed65abbSmrg goto flip_error; 3546de2362d3Smrg } 35473ed65abbSmrg 35488bf5c682Smrg if (drmmode_crtc->tear_free) { 35498bf5c682Smrg drmmode_crtc->scanout_id ^= 1; 35508bf5c682Smrg drmmode_crtc->ignore_damage = TRUE; 35518bf5c682Smrg } 35528bf5c682Smrg 355339413783Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->flip_pending, 3554446f62d6Smrg flipdata->fb[crtc_id]); 3555446f62d6Smrg 3556446f62d6Smrg next: 355718781e08Smrg drm_queue_seq = 0; 3558de2362d3Smrg } 3559de2362d3Smrg 356039413783Smrg if (handle_deferred) 356139413783Smrg radeon_drm_queue_handle_deferred(ref_crtc); 356218781e08Smrg if (flipdata->flip_count > 0) 356318781e08Smrg return TRUE; 35640d16fef4Smrg 35653ed65abbSmrgflip_error: 35663ed65abbSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n", 35673ed65abbSmrg strerror(errno)); 35683ed65abbSmrg 356918781e08Smrgerror: 357018781e08Smrg if (drm_queue_seq) 357118781e08Smrg radeon_drm_abort_entry(drm_queue_seq); 357218781e08Smrg else if (crtc) 357318781e08Smrg drmmode_flip_abort(crtc, flipdata); 35743ed65abbSmrg else { 35753ed65abbSmrg abort(NULL, data); 357618781e08Smrg free(flipdata); 35773ed65abbSmrg } 3578de2362d3Smrg 3579de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", 3580de2362d3Smrg strerror(errno)); 358139413783Smrg if (handle_deferred) 358239413783Smrg radeon_drm_queue_handle_deferred(ref_crtc); 3583de2362d3Smrg return FALSE; 3584de2362d3Smrg} 3585