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 48cd2eb4f7Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,19,99,1,0) 4918781e08Smrg#include <dri.h> 50cd2eb4f7Smrg#endif 51de2362d3Smrg 52de2362d3Smrg#include "drmmode_display.h" 53de2362d3Smrg 54de2362d3Smrg/* DPMS */ 55de2362d3Smrg#ifdef HAVE_XEXTPROTO_71 56de2362d3Smrg#include <X11/extensions/dpmsconst.h> 57de2362d3Smrg#else 58de2362d3Smrg#define DPMS_SERVER 59de2362d3Smrg#include <X11/extensions/dpms.h> 60de2362d3Smrg#endif 61de2362d3Smrg 6218781e08Smrg#define DEFAULT_NOMINAL_FRAME_RATE 60 6318781e08Smrg 6418781e08Smrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 22 6518781e08Smrg#define HAVE_NOTIFY_FD 1 6618781e08Smrg#endif 6718781e08Smrg 6818781e08Smrgstatic Bool 6918781e08Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height); 7018781e08Smrg 7118781e08Smrgstatic Bool 7218781e08SmrgRADEONZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name) 7318781e08Smrg{ 7418781e08Smrg int i = 0; 7518781e08Smrg char s1[20]; 7618781e08Smrg 7718781e08Smrg do { 7818781e08Smrg switch(*s) { 7918781e08Smrg case ',': 8018781e08Smrg s1[i] = '\0'; 8118781e08Smrg i = 0; 8218781e08Smrg if (strcmp(s1, output_name) == 0) 8318781e08Smrg return TRUE; 8418781e08Smrg break; 8518781e08Smrg case ' ': 8618781e08Smrg case '\t': 8718781e08Smrg case '\n': 8818781e08Smrg case '\r': 8918781e08Smrg break; 9018781e08Smrg default: 9118781e08Smrg s1[i] = *s; 9218781e08Smrg i++; 9318781e08Smrg break; 9418781e08Smrg } 9518781e08Smrg } while(*s++); 9618781e08Smrg 9718781e08Smrg s1[i] = '\0'; 9818781e08Smrg if (strcmp(s1, output_name) == 0) 9918781e08Smrg return TRUE; 10018781e08Smrg 10118781e08Smrg return FALSE; 10218781e08Smrg} 10318781e08Smrg 1048bf5c682Smrg 105de2362d3Smrgstatic PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn, 106de2362d3Smrg int width, int height, 107de2362d3Smrg int depth, int bpp, 10818781e08Smrg int pitch, 10939413783Smrg struct radeon_buffer *bo) 110de2362d3Smrg{ 111de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 112de2362d3Smrg ScreenPtr pScreen = pScrn->pScreen; 113de2362d3Smrg PixmapPtr pixmap; 114de2362d3Smrg 11518781e08Smrg pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 11618781e08Smrg RADEON_CREATE_PIXMAP_SCANOUT); 117de2362d3Smrg if (!pixmap) 118de2362d3Smrg return NULL; 119de2362d3Smrg 1207314432eSmrg if (!(*pScreen->ModifyPixmapHeader)(pixmap, width, height, 1217314432eSmrg depth, bpp, pitch, NULL)) { 12218781e08Smrg goto fail; 1237314432eSmrg } 1247314432eSmrg 12518781e08Smrg if (!info->use_glamor) 12618781e08Smrg exaMoveInPixmap(pixmap); 12718781e08Smrg 12818781e08Smrg if (!radeon_set_pixmap_bo(pixmap, bo)) 12918781e08Smrg goto fail; 13018781e08Smrg 13139413783Smrg if (info->surf_man && !info->use_glamor) { 13239413783Smrg struct radeon_surface *surface = radeon_get_pixmap_surface(pixmap); 13339413783Smrg 13439413783Smrg if (!radeon_surface_initialize(info, surface, width, height, bpp / 8, 13539413783Smrg radeon_get_pixmap_tiling_flags(pixmap), 0)) 13639413783Smrg goto fail; 137de2362d3Smrg } 138de2362d3Smrg 13918781e08Smrg if (!info->use_glamor || 14039413783Smrg radeon_glamor_create_textured_pixmap(pixmap, bo)) 14118781e08Smrg return pixmap; 14218781e08Smrg 14318781e08Smrgfail: 14418781e08Smrg pScreen->DestroyPixmap(pixmap); 14518781e08Smrg return NULL; 146de2362d3Smrg} 147de2362d3Smrg 148de2362d3Smrgstatic void drmmode_destroy_bo_pixmap(PixmapPtr pixmap) 149de2362d3Smrg{ 150de2362d3Smrg ScreenPtr pScreen = pixmap->drawable.pScreen; 151de2362d3Smrg 152de2362d3Smrg (*pScreen->DestroyPixmap)(pixmap); 153de2362d3Smrg} 154de2362d3Smrg 155de2362d3Smrgstatic void 156de2362d3Smrgdrmmode_ConvertFromKMode(ScrnInfoPtr scrn, 157de2362d3Smrg drmModeModeInfo *kmode, 158de2362d3Smrg DisplayModePtr mode) 159de2362d3Smrg{ 160de2362d3Smrg memset(mode, 0, sizeof(DisplayModeRec)); 161de2362d3Smrg mode->status = MODE_OK; 162de2362d3Smrg 163de2362d3Smrg mode->Clock = kmode->clock; 164de2362d3Smrg 165de2362d3Smrg mode->HDisplay = kmode->hdisplay; 166de2362d3Smrg mode->HSyncStart = kmode->hsync_start; 167de2362d3Smrg mode->HSyncEnd = kmode->hsync_end; 168de2362d3Smrg mode->HTotal = kmode->htotal; 169de2362d3Smrg mode->HSkew = kmode->hskew; 170de2362d3Smrg 171de2362d3Smrg mode->VDisplay = kmode->vdisplay; 172de2362d3Smrg mode->VSyncStart = kmode->vsync_start; 173de2362d3Smrg mode->VSyncEnd = kmode->vsync_end; 174de2362d3Smrg mode->VTotal = kmode->vtotal; 175de2362d3Smrg mode->VScan = kmode->vscan; 176de2362d3Smrg 177de2362d3Smrg mode->Flags = kmode->flags; //& FLAG_BITS; 178de2362d3Smrg mode->name = strdup(kmode->name); 179de2362d3Smrg 180de2362d3Smrg if (kmode->type & DRM_MODE_TYPE_DRIVER) 181de2362d3Smrg mode->type = M_T_DRIVER; 182de2362d3Smrg if (kmode->type & DRM_MODE_TYPE_PREFERRED) 183de2362d3Smrg mode->type |= M_T_PREFERRED; 184de2362d3Smrg xf86SetModeCrtc (mode, scrn->adjustFlags); 185de2362d3Smrg} 186de2362d3Smrg 187de2362d3Smrgstatic void 188de2362d3Smrgdrmmode_ConvertToKMode(ScrnInfoPtr scrn, 189de2362d3Smrg drmModeModeInfo *kmode, 190de2362d3Smrg DisplayModePtr mode) 191de2362d3Smrg{ 192de2362d3Smrg memset(kmode, 0, sizeof(*kmode)); 193de2362d3Smrg 194de2362d3Smrg kmode->clock = mode->Clock; 195de2362d3Smrg kmode->hdisplay = mode->HDisplay; 196de2362d3Smrg kmode->hsync_start = mode->HSyncStart; 197de2362d3Smrg kmode->hsync_end = mode->HSyncEnd; 198de2362d3Smrg kmode->htotal = mode->HTotal; 199de2362d3Smrg kmode->hskew = mode->HSkew; 200de2362d3Smrg 201de2362d3Smrg kmode->vdisplay = mode->VDisplay; 202de2362d3Smrg kmode->vsync_start = mode->VSyncStart; 203de2362d3Smrg kmode->vsync_end = mode->VSyncEnd; 204de2362d3Smrg kmode->vtotal = mode->VTotal; 205de2362d3Smrg kmode->vscan = mode->VScan; 206de2362d3Smrg 207de2362d3Smrg kmode->flags = mode->Flags; //& FLAG_BITS; 208de2362d3Smrg if (mode->name) 209de2362d3Smrg strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); 210de2362d3Smrg kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0; 211de2362d3Smrg 212de2362d3Smrg} 213de2362d3Smrg 2148bf5c682Smrg/* 2158bf5c682Smrg * Utility helper for drmWaitVBlank 2168bf5c682Smrg */ 2178bf5c682SmrgBool 2188bf5c682Smrgdrmmode_wait_vblank(xf86CrtcPtr crtc, drmVBlankSeqType type, 2198bf5c682Smrg uint32_t target_seq, unsigned long signal, uint64_t *ust, 2208bf5c682Smrg uint32_t *result_seq) 2218bf5c682Smrg{ 2228bf5c682Smrg int crtc_id = drmmode_get_crtc_id(crtc); 2238bf5c682Smrg ScrnInfoPtr scrn = crtc->scrn; 2248bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 2258bf5c682Smrg drmVBlank vbl; 2268bf5c682Smrg 2278bf5c682Smrg if (crtc_id == 1) 2288bf5c682Smrg type |= DRM_VBLANK_SECONDARY; 2298bf5c682Smrg else if (crtc_id > 1) 2308bf5c682Smrg type |= (crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT) & 2318bf5c682Smrg DRM_VBLANK_HIGH_CRTC_MASK; 2328bf5c682Smrg 2338bf5c682Smrg vbl.request.type = type; 2348bf5c682Smrg vbl.request.sequence = target_seq; 2358bf5c682Smrg vbl.request.signal = signal; 2368bf5c682Smrg 2378bf5c682Smrg if (drmWaitVBlank(pRADEONEnt->fd, &vbl) != 0) 2388bf5c682Smrg return FALSE; 2398bf5c682Smrg 2408bf5c682Smrg if (ust) 2418bf5c682Smrg *ust = (uint64_t)vbl.reply.tval_sec * 1000000 + 2428bf5c682Smrg vbl.reply.tval_usec; 2438bf5c682Smrg if (result_seq) 2448bf5c682Smrg *result_seq = vbl.reply.sequence; 2458bf5c682Smrg 2468bf5c682Smrg return TRUE; 2478bf5c682Smrg} 2488bf5c682Smrg 24918781e08Smrg/* 25018781e08Smrg * Retrieves present time in microseconds that is compatible 25118781e08Smrg * with units used by vblank timestamps. Depending on the kernel 25218781e08Smrg * version and DRM kernel module configuration, the vblank 25318781e08Smrg * timestamp can either be in real time or monotonic time 25418781e08Smrg */ 25518781e08Smrgint drmmode_get_current_ust(int drm_fd, CARD64 *ust) 25618781e08Smrg{ 25718781e08Smrg uint64_t cap_value; 25818781e08Smrg int ret; 25918781e08Smrg struct timespec now; 26018781e08Smrg 26118781e08Smrg ret = drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap_value); 26218781e08Smrg if (ret || !cap_value) 26318781e08Smrg /* old kernel or drm_timestamp_monotonic turned off */ 26418781e08Smrg ret = clock_gettime(CLOCK_REALTIME, &now); 26518781e08Smrg else 26618781e08Smrg ret = clock_gettime(CLOCK_MONOTONIC, &now); 26718781e08Smrg if (ret) 26818781e08Smrg return ret; 26918781e08Smrg *ust = ((CARD64)now.tv_sec * 1000000) + ((CARD64)now.tv_nsec / 1000); 27018781e08Smrg return 0; 27118781e08Smrg} 27218781e08Smrg 27318781e08Smrg/* 27418781e08Smrg * Get current frame count and frame count timestamp of the crtc. 27518781e08Smrg */ 27618781e08Smrgint drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc) 27718781e08Smrg{ 27818781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 2798bf5c682Smrg uint32_t seq; 28018781e08Smrg 2818bf5c682Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, ust, &seq)) { 28218781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 28318781e08Smrg "get vblank counter failed: %s\n", strerror(errno)); 2848bf5c682Smrg return -1; 28518781e08Smrg } 28618781e08Smrg 2878bf5c682Smrg *msc = seq; 28818781e08Smrg 28918781e08Smrg return Success; 29018781e08Smrg} 29118781e08Smrg 292de2362d3Smrgstatic void 29318781e08Smrgdrmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode) 294de2362d3Smrg{ 295de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 29618781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 2978bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 29818781e08Smrg CARD64 ust; 29918781e08Smrg int ret; 3007314432eSmrg 30118781e08Smrg if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) { 3028bf5c682Smrg uint32_t seq; 30318781e08Smrg 30439413783Smrg radeon_drm_wait_pending_flip(crtc); 30518781e08Smrg 30618781e08Smrg /* 30718781e08Smrg * On->Off transition: record the last vblank time, 30818781e08Smrg * sequence number and frame period. 30918781e08Smrg */ 3108bf5c682Smrg if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, &ust, 3118bf5c682Smrg &seq)) 31218781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 31318781e08Smrg "%s cannot get last vblank counter\n", 31418781e08Smrg __func__); 31518781e08Smrg else { 31618781e08Smrg CARD64 nominal_frame_rate, pix_in_frame; 31718781e08Smrg 31818781e08Smrg drmmode_crtc->dpms_last_ust = ust; 31918781e08Smrg drmmode_crtc->dpms_last_seq = seq; 32018781e08Smrg nominal_frame_rate = crtc->mode.Clock; 32118781e08Smrg nominal_frame_rate *= 1000; 32218781e08Smrg pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal; 32318781e08Smrg if (nominal_frame_rate == 0 || pix_in_frame == 0) 32418781e08Smrg nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE; 32518781e08Smrg else 32618781e08Smrg nominal_frame_rate /= pix_in_frame; 32718781e08Smrg drmmode_crtc->dpms_last_fps = nominal_frame_rate; 32818781e08Smrg } 32939413783Smrg 33039413783Smrg drmmode_crtc->dpms_mode = mode; 33139413783Smrg radeon_drm_queue_handle_deferred(crtc); 33218781e08Smrg } else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) { 33318781e08Smrg /* 33418781e08Smrg * Off->On transition: calculate and accumulate the 33518781e08Smrg * number of interpolated vblanks while we were in Off state 33618781e08Smrg */ 3378bf5c682Smrg ret = drmmode_get_current_ust(pRADEONEnt->fd, &ust); 33818781e08Smrg if (ret) 33918781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 34018781e08Smrg "%s cannot get current time\n", __func__); 34118781e08Smrg else if (drmmode_crtc->dpms_last_ust) { 34218781e08Smrg CARD64 time_elapsed, delta_seq; 34318781e08Smrg time_elapsed = ust - drmmode_crtc->dpms_last_ust; 34418781e08Smrg delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps; 34518781e08Smrg delta_seq /= 1000000; 34618781e08Smrg drmmode_crtc->interpolated_vblanks += delta_seq; 34718781e08Smrg 34818781e08Smrg } 34939413783Smrg 35039413783Smrg drmmode_crtc->dpms_mode = DPMSModeOn; 3517821949aSmrg } 35218781e08Smrg} 35318781e08Smrg 35418781e08Smrgstatic void 35518781e08Smrgdrmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) 35618781e08Smrg{ 35718781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 3588bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 35918781e08Smrg 36018781e08Smrg /* Disable unused CRTCs */ 36118781e08Smrg if (!crtc->enabled || mode != DPMSModeOn) { 36239413783Smrg drmmode_do_crtc_dpms(crtc, DPMSModeOff); 3638bf5c682Smrg drmModeSetCrtc(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 36418781e08Smrg 0, 0, 0, NULL, 0, NULL); 3658bf5c682Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, NULL); 36618781e08Smrg } else if (drmmode_crtc->dpms_mode != DPMSModeOn) 36718781e08Smrg crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, 36818781e08Smrg crtc->x, crtc->y); 369de2362d3Smrg} 370de2362d3Smrg 371de2362d3Smrgstatic PixmapPtr 372de2362d3Smrgcreate_pixmap_for_fbcon(drmmode_ptr drmmode, 373de2362d3Smrg ScrnInfoPtr pScrn, int fbcon_id) 374de2362d3Smrg{ 3758bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 37618781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 37718781e08Smrg PixmapPtr pixmap = info->fbcon_pixmap; 378b338b52fSmrg struct radeon_buffer *bo = NULL; 379de2362d3Smrg drmModeFBPtr fbcon; 380de2362d3Smrg struct drm_gem_flink flink; 381de2362d3Smrg 38218781e08Smrg if (pixmap) 38318781e08Smrg return pixmap; 38418781e08Smrg 3858bf5c682Smrg fbcon = drmModeGetFB(pRADEONEnt->fd, fbcon_id); 38639413783Smrg if (!fbcon) 387de2362d3Smrg return NULL; 388de2362d3Smrg 389de2362d3Smrg if (fbcon->depth != pScrn->depth || 390de2362d3Smrg fbcon->width != pScrn->virtualX || 391de2362d3Smrg fbcon->height != pScrn->virtualY) 392de2362d3Smrg goto out_free_fb; 393de2362d3Smrg 394de2362d3Smrg flink.handle = fbcon->handle; 3958bf5c682Smrg if (ioctl(pRADEONEnt->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) { 396de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 397de2362d3Smrg "Couldn't flink fbcon handle\n"); 398de2362d3Smrg goto out_free_fb; 399de2362d3Smrg } 400de2362d3Smrg 40139413783Smrg bo = calloc(1, sizeof(struct radeon_buffer)); 40239413783Smrg if (!bo) { 403de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 40439413783Smrg "Couldn't allocate BO for fbcon handle\n"); 40539413783Smrg goto out_free_fb; 40639413783Smrg } 40739413783Smrg bo->ref_count = 1; 40839413783Smrg 40939413783Smrg bo->bo.radeon = radeon_bo_open(drmmode->bufmgr, flink.name, 0, 0, 0, 0); 410b338b52fSmrg if (!bo->bo.radeon) { 41139413783Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 41239413783Smrg "Couldn't open BO for fbcon handle\n"); 413de2362d3Smrg goto out_free_fb; 414de2362d3Smrg } 415de2362d3Smrg 416de2362d3Smrg pixmap = drmmode_create_bo_pixmap(pScrn, fbcon->width, fbcon->height, 41718781e08Smrg fbcon->depth, fbcon->bpp, fbcon->pitch, 41839413783Smrg bo); 41918781e08Smrg info->fbcon_pixmap = pixmap; 420de2362d3Smrgout_free_fb: 421b338b52fSmrg radeon_buffer_unref(&bo); 422de2362d3Smrg drmModeFreeFB(fbcon); 423de2362d3Smrg return pixmap; 424de2362d3Smrg} 425de2362d3Smrg 42618781e08Smrgstatic void 42718781e08Smrgdestroy_pixmap_for_fbcon(ScrnInfoPtr pScrn) 42818781e08Smrg{ 42918781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 43018781e08Smrg 43118781e08Smrg /* XXX: The current GPUVM support in the kernel doesn't allow removing 43218781e08Smrg * the virtual address range for this BO, so we need to keep around 43318781e08Smrg * the pixmap to avoid breaking glamor with GPUVM 43439413783Smrg * 43539413783Smrg * Similarly, need to keep around the pixmap with current glamor, to 43639413783Smrg * avoid issues due to a GEM handle lifetime conflict between us and 43739413783Smrg * Mesa 43818781e08Smrg */ 43939413783Smrg if (info->use_glamor && 44039413783Smrg (info->ChipFamily >= CHIP_FAMILY_CAYMAN || 44139413783Smrg xorgGetVersion() >= XORG_VERSION_NUMERIC(1,19,99,1,0))) 44218781e08Smrg return; 44318781e08Smrg 44418781e08Smrg if (info->fbcon_pixmap) 44518781e08Smrg pScrn->pScreen->DestroyPixmap(info->fbcon_pixmap); 44618781e08Smrg info->fbcon_pixmap = NULL; 44718781e08Smrg} 44818781e08Smrg 449de2362d3Smrgvoid drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 450de2362d3Smrg{ 451de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 452de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 453de2362d3Smrg ScreenPtr pScreen = pScrn->pScreen; 4548bf5c682Smrg PixmapPtr src, dst = pScreen->GetScreenPixmap(pScreen); 4558bf5c682Smrg struct drmmode_fb *fb = radeon_pixmap_get_fb(dst); 456de2362d3Smrg int fbcon_id = 0; 45718781e08Smrg Bool force; 45818781e08Smrg GCPtr gc; 459de2362d3Smrg int i; 460de2362d3Smrg 461de2362d3Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 462de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private; 463de2362d3Smrg 464de2362d3Smrg if (drmmode_crtc->mode_crtc->buffer_id) 465de2362d3Smrg fbcon_id = drmmode_crtc->mode_crtc->buffer_id; 466de2362d3Smrg } 467de2362d3Smrg 468de2362d3Smrg if (!fbcon_id) 46918781e08Smrg return; 47018781e08Smrg 4718bf5c682Smrg if (fbcon_id == fb->handle) { 47218781e08Smrg /* in some rare case there might be no fbcon and we might already 47318781e08Smrg * be the one with the current fb to avoid a false deadlck in 47418781e08Smrg * kernel ttm code just do nothing as anyway there is nothing 47518781e08Smrg * to do 47618781e08Smrg */ 47718781e08Smrg return; 47818781e08Smrg } 479de2362d3Smrg 480de2362d3Smrg src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id); 481de2362d3Smrg if (!src) 48218781e08Smrg return; 4830d16fef4Smrg 48418781e08Smrg gc = GetScratchGC(pScrn->depth, pScreen); 48518781e08Smrg ValidateGC(&dst->drawable, gc); 48618781e08Smrg 48718781e08Smrg force = info->accel_state->force; 48818781e08Smrg info->accel_state->force = TRUE; 48918781e08Smrg (*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0, 49018781e08Smrg pScrn->virtualX, pScrn->virtualY, 0, 0); 49118781e08Smrg info->accel_state->force = force; 49218781e08Smrg 49318781e08Smrg FreeScratchGC(gc); 494de2362d3Smrg 495de2362d3Smrg pScreen->canDoBGNoneRoot = TRUE; 49618781e08Smrg destroy_pixmap_for_fbcon(pScrn); 4977821949aSmrg return; 49818781e08Smrg} 4990d16fef4Smrg 5008bf5c682Smrgvoid 50118781e08Smrgdrmmode_crtc_scanout_destroy(drmmode_ptr drmmode, 50218781e08Smrg struct drmmode_scanout *scanout) 50318781e08Smrg{ 50418781e08Smrg if (scanout->pixmap) { 50518781e08Smrg drmmode_destroy_bo_pixmap(scanout->pixmap); 50618781e08Smrg scanout->pixmap = NULL; 50718781e08Smrg } 50818781e08Smrg 50939413783Smrg radeon_buffer_unref(&scanout->bo); 51018781e08Smrg} 51118781e08Smrg 5128bf5c682Smrgvoid 513446f62d6Smrgdrmmode_crtc_scanout_free(xf86CrtcPtr crtc) 51418781e08Smrg{ 515446f62d6Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 516446f62d6Smrg 517446f62d6Smrg if (drmmode_crtc->scanout_update_pending) { 518446f62d6Smrg radeon_drm_wait_pending_flip(crtc); 519446f62d6Smrg radeon_drm_abort_entry(drmmode_crtc->scanout_update_pending); 520446f62d6Smrg drmmode_crtc->scanout_update_pending = 0; 521446f62d6Smrg radeon_drm_queue_handle_deferred(crtc); 522446f62d6Smrg } 523446f62d6Smrg 5248bf5c682Smrg drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 5258bf5c682Smrg &drmmode_crtc->scanout[0]); 5268bf5c682Smrg drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 5278bf5c682Smrg &drmmode_crtc->scanout[1]); 52818781e08Smrg 5298bf5c682Smrg if (drmmode_crtc->scanout_damage) 53018781e08Smrg DamageDestroy(drmmode_crtc->scanout_damage); 53118781e08Smrg} 53218781e08Smrg 5338bf5c682SmrgPixmapPtr 5343ed65abbSmrgdrmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout, 5353ed65abbSmrg int width, int height) 53618781e08Smrg{ 53718781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 53818781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 53918781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 54018781e08Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 54118781e08Smrg struct radeon_surface surface; 54218781e08Smrg uint32_t tiling = RADEON_CREATE_PIXMAP_TILING_MACRO; 54318781e08Smrg int pitch; 54418781e08Smrg 5453ed65abbSmrg if (scanout->pixmap) { 54618781e08Smrg if (scanout->width == width && scanout->height == height) 5473ed65abbSmrg return scanout->pixmap; 54818781e08Smrg 54918781e08Smrg drmmode_crtc_scanout_destroy(drmmode, scanout); 55018781e08Smrg } 55118781e08Smrg 55218781e08Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) 55318781e08Smrg tiling |= RADEON_CREATE_PIXMAP_TILING_MICRO; 55418781e08Smrg scanout->bo = radeon_alloc_pixmap_bo(pScrn, width, height, pScrn->depth, 55518781e08Smrg tiling, pScrn->bitsPerPixel, 55618781e08Smrg &pitch, &surface, &tiling); 5578bf5c682Smrg if (!scanout->bo) { 5588bf5c682Smrg ErrorF("failed to create CRTC scanout BO\n"); 5598bf5c682Smrg return NULL; 56018781e08Smrg } 56118781e08Smrg 56218781e08Smrg scanout->pixmap = drmmode_create_bo_pixmap(pScrn, 56318781e08Smrg width, height, 56418781e08Smrg pScrn->depth, 56518781e08Smrg pScrn->bitsPerPixel, 56639413783Smrg pitch, scanout->bo); 5678bf5c682Smrg if (!scanout->pixmap) { 5688bf5c682Smrg ErrorF("failed to create CRTC scanout pixmap\n"); 5698bf5c682Smrg goto error; 5708bf5c682Smrg } 5718bf5c682Smrg 5728bf5c682Smrg if (radeon_pixmap_get_fb(scanout->pixmap)) { 5733ed65abbSmrg scanout->width = width; 5743ed65abbSmrg scanout->height = height; 5753ed65abbSmrg } else { 5768bf5c682Smrg ErrorF("failed to create CRTC scanout FB\n"); 5778bf5c682Smrgerror: 5783ed65abbSmrg drmmode_crtc_scanout_destroy(drmmode, scanout); 5793ed65abbSmrg } 58018781e08Smrg 58118781e08Smrg return scanout->pixmap; 58218781e08Smrg} 58318781e08Smrg 58418781e08Smrgstatic void 58518781e08Smrgradeon_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure) 58618781e08Smrg{ 5878bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc = closure; 5888bf5c682Smrg 5898bf5c682Smrg if (drmmode_crtc->ignore_damage) { 5908bf5c682Smrg RegionEmpty(&damage->damage); 5918bf5c682Smrg drmmode_crtc->ignore_damage = FALSE; 5928bf5c682Smrg return; 5938bf5c682Smrg } 5948bf5c682Smrg 59518781e08Smrg /* Only keep track of the extents */ 59618781e08Smrg RegionUninit(&damage->damage); 59718781e08Smrg damage->damage.data = NULL; 59818781e08Smrg} 59918781e08Smrg 6008bf5c682Smrgstatic void 6018bf5c682Smrgdrmmode_screen_damage_destroy(DamagePtr damage, void *closure) 6028bf5c682Smrg{ 6038bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc = closure; 6048bf5c682Smrg 6058bf5c682Smrg drmmode_crtc->scanout_damage = NULL; 6068bf5c682Smrg RegionUninit(&drmmode_crtc->scanout_last_region); 6078bf5c682Smrg} 6088bf5c682Smrg 60918781e08Smrgstatic Bool 61018781e08Smrgdrmmode_can_use_hw_cursor(xf86CrtcPtr crtc) 61118781e08Smrg{ 61218781e08Smrg RADEONInfoPtr info = RADEONPTR(crtc->scrn); 61318781e08Smrg 61418781e08Smrg /* Check for Option "SWcursor" */ 61518781e08Smrg if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) 61618781e08Smrg return FALSE; 61718781e08Smrg 61818781e08Smrg /* Fall back to SW cursor if the CRTC is transformed */ 61918781e08Smrg if (crtc->transformPresent) 62018781e08Smrg return FALSE; 6210d16fef4Smrg 6228bf5c682Smrg#if XF86_CRTC_VERSION < 7 62318781e08Smrg /* Xorg doesn't correctly handle cursor position transform in the 62418781e08Smrg * rotation case 62518781e08Smrg */ 62618781e08Smrg if (crtc->driverIsPerformingTransform && 62718781e08Smrg (crtc->rotation & 0xf) != RR_Rotate_0) 62818781e08Smrg return FALSE; 62918781e08Smrg#endif 63018781e08Smrg 63118781e08Smrg /* HW cursor not supported with RandR 1.4 multihead up to 1.18.99.901 */ 63218781e08Smrg if (xorgGetVersion() <= XORG_VERSION_NUMERIC(1,18,99,901,0) && 63318781e08Smrg !xorg_list_is_empty(&crtc->scrn->pScreen->pixmap_dirty_list)) 63418781e08Smrg return FALSE; 63518781e08Smrg 63618781e08Smrg return TRUE; 63718781e08Smrg} 63818781e08Smrg 6393ed65abbSmrgstatic void 6403ed65abbSmrgdrmmode_crtc_update_tear_free(xf86CrtcPtr crtc) 6413ed65abbSmrg{ 6423ed65abbSmrg RADEONInfoPtr info = RADEONPTR(crtc->scrn); 6433ed65abbSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 6443ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 6453ed65abbSmrg int i; 6463ed65abbSmrg 6473ed65abbSmrg drmmode_crtc->tear_free = FALSE; 6483ed65abbSmrg 6493ed65abbSmrg for (i = 0; i < xf86_config->num_output; i++) { 6503ed65abbSmrg xf86OutputPtr output = xf86_config->output[i]; 6513ed65abbSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 6523ed65abbSmrg 6533ed65abbSmrg if (output->crtc != crtc) 6543ed65abbSmrg continue; 6553ed65abbSmrg 6563ed65abbSmrg if (drmmode_output->tear_free == 1 || 6573ed65abbSmrg (drmmode_output->tear_free == 2 && 6588bf5c682Smrg (crtc->scrn->pScreen->isGPU || 6593ed65abbSmrg info->shadow_primary || 6603ed65abbSmrg crtc->transformPresent || crtc->rotation != RR_Rotate_0))) { 6613ed65abbSmrg drmmode_crtc->tear_free = TRUE; 6623ed65abbSmrg return; 6633ed65abbSmrg } 6643ed65abbSmrg } 6653ed65abbSmrg} 6663ed65abbSmrg 6673ed65abbSmrg#if XF86_CRTC_VERSION < 7 6683ed65abbSmrg#define XF86DriverTransformOutput TRUE 6693ed65abbSmrg#define XF86DriverTransformNone FALSE 6703ed65abbSmrg#endif 6713ed65abbSmrg 67218781e08Smrgstatic Bool 67318781e08Smrgdrmmode_handle_transform(xf86CrtcPtr crtc) 67418781e08Smrg{ 67518781e08Smrg Bool ret; 67618781e08Smrg 6778bf5c682Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 67839413783Smrg crtc->driverIsPerformingTransform = XF86DriverTransformOutput; 6798bf5c682Smrg#else 6808bf5c682Smrg crtc->driverIsPerformingTransform = !crtc->transformPresent && 6818bf5c682Smrg (crtc->rotation & 0xf) == RR_Rotate_0; 6828bf5c682Smrg#endif 68318781e08Smrg 68418781e08Smrg ret = xf86CrtcRotate(crtc); 68518781e08Smrg 68618781e08Smrg crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use; 68718781e08Smrg 68818781e08Smrg return ret; 6890d16fef4Smrg} 6900d16fef4Smrg 6913ed65abbSmrg 6923ed65abbSmrgstatic void 6933ed65abbSmrgdrmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, 6948bf5c682Smrg unsigned scanout_id, struct drmmode_fb **fb, 6958bf5c682Smrg int *x, int *y) 6963ed65abbSmrg{ 6973ed65abbSmrg ScrnInfoPtr scrn = crtc->scrn; 6983ed65abbSmrg ScreenPtr screen = scrn->pScreen; 6993ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 7003ed65abbSmrg 7013ed65abbSmrg if (drmmode_crtc->tear_free && 7023ed65abbSmrg !drmmode_crtc->scanout[1].pixmap) { 7033ed65abbSmrg RegionPtr region; 7043ed65abbSmrg BoxPtr box; 7053ed65abbSmrg 7063ed65abbSmrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 7073ed65abbSmrg mode->HDisplay, 7083ed65abbSmrg mode->VDisplay); 7093ed65abbSmrg region = &drmmode_crtc->scanout_last_region; 7103ed65abbSmrg RegionUninit(region); 7113ed65abbSmrg region->data = NULL; 7123ed65abbSmrg box = RegionExtents(region); 7133ed65abbSmrg box->x1 = crtc->x; 7143ed65abbSmrg box->y1 = crtc->y; 7153ed65abbSmrg box->x2 = crtc->x + mode->HDisplay; 7163ed65abbSmrg box->y2 = crtc->y + mode->VDisplay; 7173ed65abbSmrg } 7183ed65abbSmrg 7193ed65abbSmrg if (scanout_id != drmmode_crtc->scanout_id) { 7203ed65abbSmrg PixmapDirtyUpdatePtr dirty = NULL; 7213ed65abbSmrg 7223ed65abbSmrg xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, 7233ed65abbSmrg ent) { 7248bf5c682Smrg if (radeon_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) { 725cd2eb4f7Smrg dirty->secondary_dst = 7263ed65abbSmrg drmmode_crtc->scanout[scanout_id].pixmap; 7273ed65abbSmrg break; 7283ed65abbSmrg } 7293ed65abbSmrg } 7303ed65abbSmrg 7313ed65abbSmrg if (!drmmode_crtc->tear_free) { 7323ed65abbSmrg GCPtr gc = GetScratchGC(scrn->depth, screen); 7333ed65abbSmrg 7343ed65abbSmrg ValidateGC(&drmmode_crtc->scanout[0].pixmap->drawable, gc); 7353ed65abbSmrg gc->ops->CopyArea(&drmmode_crtc->scanout[1].pixmap->drawable, 7363ed65abbSmrg &drmmode_crtc->scanout[0].pixmap->drawable, 7373ed65abbSmrg gc, 0, 0, mode->HDisplay, mode->VDisplay, 7383ed65abbSmrg 0, 0); 7393ed65abbSmrg FreeScratchGC(gc); 74039413783Smrg radeon_finish(scrn, drmmode_crtc->scanout[0].bo); 7413ed65abbSmrg } 7423ed65abbSmrg } 7433ed65abbSmrg 7448bf5c682Smrg *fb = radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap); 7453ed65abbSmrg *x = *y = 0; 7463ed65abbSmrg drmmode_crtc->scanout_id = scanout_id; 7473ed65abbSmrg} 7483ed65abbSmrg 7493ed65abbSmrg 7503ed65abbSmrgstatic void 7513ed65abbSmrgdrmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, 7528bf5c682Smrg unsigned scanout_id, struct drmmode_fb **fb, int *x, 7538bf5c682Smrg int *y) 7543ed65abbSmrg{ 7553ed65abbSmrg ScrnInfoPtr scrn = crtc->scrn; 7563ed65abbSmrg ScreenPtr screen = scrn->pScreen; 7573ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 7583ed65abbSmrg 7598bf5c682Smrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[scanout_id], 7603ed65abbSmrg mode->HDisplay, mode->VDisplay); 7613ed65abbSmrg if (drmmode_crtc->tear_free) { 7628bf5c682Smrg drmmode_crtc_scanout_create(crtc, 7638bf5c682Smrg &drmmode_crtc->scanout[scanout_id ^ 1], 7643ed65abbSmrg mode->HDisplay, mode->VDisplay); 7653ed65abbSmrg } 7663ed65abbSmrg 7678bf5c682Smrg if (drmmode_crtc->scanout[scanout_id].pixmap && 7688bf5c682Smrg (!drmmode_crtc->tear_free || 7698bf5c682Smrg drmmode_crtc->scanout[scanout_id ^ 1].pixmap)) { 77039413783Smrg BoxRec extents = { .x1 = 0, .y1 = 0, 77139413783Smrg .x2 = scrn->virtualX, .y2 = scrn->virtualY }; 7723ed65abbSmrg 7733ed65abbSmrg if (!drmmode_crtc->scanout_damage) { 7743ed65abbSmrg drmmode_crtc->scanout_damage = 7753ed65abbSmrg DamageCreate(radeon_screen_damage_report, 7768bf5c682Smrg drmmode_screen_damage_destroy, 7778bf5c682Smrg DamageReportRawRegion, 7788bf5c682Smrg TRUE, screen, drmmode_crtc); 7798bf5c682Smrg DamageRegister(&screen->root->drawable, 7803ed65abbSmrg drmmode_crtc->scanout_damage); 7813ed65abbSmrg } 7823ed65abbSmrg 7838bf5c682Smrg *fb = radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap); 7843ed65abbSmrg *x = *y = 0; 7853ed65abbSmrg 786446f62d6Smrg if (radeon_scanout_do_update(crtc, scanout_id, 787446f62d6Smrg screen->GetWindowPixmap(screen->root), 788446f62d6Smrg extents)) { 789446f62d6Smrg RegionEmpty(DamageRegion(drmmode_crtc->scanout_damage)); 790446f62d6Smrg radeon_finish(scrn, drmmode_crtc->scanout[scanout_id].bo); 791446f62d6Smrg 792446f62d6Smrg if (!drmmode_crtc->flip_pending) { 793446f62d6Smrg radeon_drm_abort_entry(drmmode_crtc-> 794446f62d6Smrg scanout_update_pending); 795446f62d6Smrg } 796446f62d6Smrg } 7973ed65abbSmrg } 7983ed65abbSmrg} 7993ed65abbSmrg 8008bf5c682Smrgstatic void 8018bf5c682Smrgdrmmode_crtc_gamma_do_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 8028bf5c682Smrg uint16_t *blue, int size) 8038bf5c682Smrg{ 8048bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 8058bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 8068bf5c682Smrg 8078bf5c682Smrg drmModeCrtcSetGamma(pRADEONEnt->fd, 8088bf5c682Smrg drmmode_crtc->mode_crtc->crtc_id, size, red, green, 8098bf5c682Smrg blue); 8108bf5c682Smrg} 8118bf5c682Smrg 8128bf5c682SmrgBool 8138bf5c682Smrgdrmmode_set_mode(xf86CrtcPtr crtc, struct drmmode_fb *fb, DisplayModePtr mode, 8148bf5c682Smrg int x, int y) 8158bf5c682Smrg{ 8168bf5c682Smrg ScrnInfoPtr scrn = crtc->scrn; 8178bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 8188bf5c682Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 8198bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 8208bf5c682Smrg uint32_t *output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); 8218bf5c682Smrg int output_count = 0; 8228bf5c682Smrg drmModeModeInfo kmode; 8238bf5c682Smrg Bool ret; 8248bf5c682Smrg int i; 8258bf5c682Smrg 8268bf5c682Smrg if (!output_ids) 8278bf5c682Smrg return FALSE; 8288bf5c682Smrg 8298bf5c682Smrg for (i = 0; i < xf86_config->num_output; i++) { 8308bf5c682Smrg xf86OutputPtr output = xf86_config->output[i]; 8318bf5c682Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 8328bf5c682Smrg 8338bf5c682Smrg if (output->crtc != crtc) 8348bf5c682Smrg continue; 8358bf5c682Smrg 8368bf5c682Smrg output_ids[output_count] = drmmode_output->mode_output->connector_id; 8378bf5c682Smrg output_count++; 8388bf5c682Smrg } 8398bf5c682Smrg 8408bf5c682Smrg drmmode_ConvertToKMode(scrn, &kmode, mode); 8418bf5c682Smrg 8428bf5c682Smrg ret = drmModeSetCrtc(pRADEONEnt->fd, 8438bf5c682Smrg drmmode_crtc->mode_crtc->crtc_id, 8448bf5c682Smrg fb->handle, x, y, output_ids, 8458bf5c682Smrg output_count, &kmode) == 0; 8468bf5c682Smrg 8478bf5c682Smrg if (ret) { 8488bf5c682Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, fb); 8498bf5c682Smrg } else { 8508bf5c682Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 8518bf5c682Smrg "failed to set mode: %s\n", strerror(errno)); 8528bf5c682Smrg } 8538bf5c682Smrg 8548bf5c682Smrg free(output_ids); 8558bf5c682Smrg return ret; 8568bf5c682Smrg} 8578bf5c682Smrg 858de2362d3Smrgstatic Bool 859de2362d3Smrgdrmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 860de2362d3Smrg Rotation rotation, int x, int y) 861de2362d3Smrg{ 862de2362d3Smrg ScrnInfoPtr pScrn = crtc->scrn; 86318781e08Smrg ScreenPtr pScreen = pScrn->pScreen; 864de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 8658bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 866de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 867de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 868446f62d6Smrg Bool handle_deferred = FALSE; 8693ed65abbSmrg unsigned scanout_id = 0; 870de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 871de2362d3Smrg int saved_x, saved_y; 872de2362d3Smrg Rotation saved_rotation; 873de2362d3Smrg DisplayModeRec saved_mode; 87418781e08Smrg Bool ret = FALSE; 875d1d00eb7Sjmcneill uint32_t handle; 876de2362d3Smrg int i; 8778bf5c682Smrg struct drmmode_fb *fb = NULL; 8788bf5c682Smrg 8798bf5c682Smrg /* The root window contents may be undefined before the WindowExposures 8808bf5c682Smrg * hook is called for it, so bail if we get here before that 8818bf5c682Smrg */ 8828bf5c682Smrg if (pScreen->WindowExposures == RADEONWindowExposures_oneshot) 8838bf5c682Smrg return FALSE; 884de2362d3Smrg 885de2362d3Smrg saved_mode = crtc->mode; 886de2362d3Smrg saved_x = crtc->x; 887de2362d3Smrg saved_y = crtc->y; 888de2362d3Smrg saved_rotation = crtc->rotation; 889de2362d3Smrg 890de2362d3Smrg if (mode) { 891de2362d3Smrg crtc->mode = *mode; 892de2362d3Smrg crtc->x = x; 893de2362d3Smrg crtc->y = y; 894de2362d3Smrg crtc->rotation = rotation; 895de2362d3Smrg 89618781e08Smrg if (!drmmode_handle_transform(crtc)) 897de2362d3Smrg goto done; 89818781e08Smrg 8993ed65abbSmrg drmmode_crtc_update_tear_free(crtc); 9003ed65abbSmrg if (drmmode_crtc->tear_free) 9013ed65abbSmrg scanout_id = drmmode_crtc->scanout_id; 90239413783Smrg else 90339413783Smrg drmmode_crtc->scanout_id = 0; 904de2362d3Smrg 9058bf5c682Smrg if (drmmode_crtc->prime_scanout_pixmap) { 9063ed65abbSmrg drmmode_crtc_prime_scanout_update(crtc, mode, scanout_id, 9078bf5c682Smrg &fb, &x, &y); 9088bf5c682Smrg } else if (drmmode_crtc->rotate.pixmap) { 9098bf5c682Smrg fb = radeon_pixmap_get_fb(drmmode_crtc->rotate.pixmap); 91018781e08Smrg x = y = 0; 91118781e08Smrg 9128bf5c682Smrg } else if (!pScreen->isGPU && 9133ed65abbSmrg (drmmode_crtc->tear_free || 91418781e08Smrg crtc->driverIsPerformingTransform || 91518781e08Smrg info->shadow_primary)) { 9163ed65abbSmrg drmmode_crtc_scanout_update(crtc, mode, scanout_id, 9178bf5c682Smrg &fb, &x, &y); 918de2362d3Smrg } 91918781e08Smrg 9208bf5c682Smrg if (!fb) 9218bf5c682Smrg fb = radeon_pixmap_get_fb(pScreen->GetWindowPixmap(pScreen->root)); 9228bf5c682Smrg if (!fb) { 923d1d00eb7Sjmcneill if (info->front_buffer->flags & RADEON_BO_FLAGS_GBM) { 924d1d00eb7Sjmcneill handle = gbm_bo_get_handle(info->front_buffer->bo.gbm).u32; 925d1d00eb7Sjmcneill } else { 926d1d00eb7Sjmcneill handle = info->front_buffer->bo.radeon->handle; 927d1d00eb7Sjmcneill } 9288bf5c682Smrg fb = radeon_fb_create(pScrn, pRADEONEnt->fd, 9298bf5c682Smrg pScrn->virtualX, pScrn->virtualY, 9308bf5c682Smrg pScrn->displayWidth * info->pixel_bytes, 931d1d00eb7Sjmcneill handle); 9328bf5c682Smrg /* Prevent refcnt of ad-hoc FBs from reaching 2 */ 9338bf5c682Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, NULL); 9348bf5c682Smrg drmmode_crtc->fb = fb; 9358bf5c682Smrg } 9368bf5c682Smrg if (!fb) { 9378bf5c682Smrg ErrorF("failed to add FB for modeset\n"); 9388bf5c682Smrg goto done; 93918781e08Smrg } 94018781e08Smrg 94139413783Smrg radeon_drm_wait_pending_flip(crtc); 942446f62d6Smrg handle_deferred = TRUE; 9438bf5c682Smrg 9448bf5c682Smrg if (!drmmode_set_mode(crtc, fb, mode, x, y)) 94518781e08Smrg goto done; 9468bf5c682Smrg 9478bf5c682Smrg ret = TRUE; 948de2362d3Smrg 94918781e08Smrg if (pScreen) 95018781e08Smrg xf86CrtcSetScreenSubpixelOrder(pScreen); 95118781e08Smrg 95218781e08Smrg drmmode_crtc->need_modeset = FALSE; 95318781e08Smrg 954de2362d3Smrg /* go through all the outputs and force DPMS them back on? */ 955de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 956de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 957de2362d3Smrg 958de2362d3Smrg if (output->crtc != crtc) 959de2362d3Smrg continue; 960de2362d3Smrg 961de2362d3Smrg output->funcs->dpms(output, DPMSModeOn); 962de2362d3Smrg } 963de2362d3Smrg } 964de2362d3Smrg 96518781e08Smrg /* Compute index of this CRTC into xf86_config->crtc */ 96618781e08Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 96718781e08Smrg if (xf86_config->crtc[i] != crtc) 96818781e08Smrg continue; 96918781e08Smrg 97018781e08Smrg if (!crtc->enabled || drmmode_can_use_hw_cursor(crtc)) 97118781e08Smrg info->hwcursor_disabled &= ~(1 << i); 97218781e08Smrg else 97318781e08Smrg info->hwcursor_disabled |= 1 << i; 97418781e08Smrg 97518781e08Smrg break; 97618781e08Smrg } 97718781e08Smrg 97818781e08Smrg#ifndef HAVE_XF86_CURSOR_RESET_CURSOR 97918781e08Smrg if (!info->hwcursor_disabled) 98018781e08Smrg xf86_reload_cursors(pScreen); 98118781e08Smrg#endif 982de2362d3Smrg 983de2362d3Smrgdone: 984de2362d3Smrg if (!ret) { 985de2362d3Smrg crtc->x = saved_x; 986de2362d3Smrg crtc->y = saved_y; 987de2362d3Smrg crtc->rotation = saved_rotation; 988de2362d3Smrg crtc->mode = saved_mode; 98918781e08Smrg } else { 9907821949aSmrg crtc->active = TRUE; 99118781e08Smrg 9928bf5c682Smrg if (drmmode_crtc->scanout[scanout_id].pixmap && 9938bf5c682Smrg fb != radeon_pixmap_get_fb(drmmode_crtc-> 99439413783Smrg scanout[scanout_id].pixmap)) { 995446f62d6Smrg drmmode_crtc_scanout_free(crtc); 99639413783Smrg } else if (!drmmode_crtc->tear_free) { 9973ed65abbSmrg drmmode_crtc_scanout_destroy(drmmode, 9983ed65abbSmrg &drmmode_crtc->scanout[1]); 9993ed65abbSmrg } 100018781e08Smrg } 100118781e08Smrg 1002446f62d6Smrg if (handle_deferred) 1003446f62d6Smrg radeon_drm_queue_handle_deferred(crtc); 1004446f62d6Smrg 1005de2362d3Smrg return ret; 1006de2362d3Smrg} 1007de2362d3Smrg 1008de2362d3Smrgstatic void 1009de2362d3Smrgdrmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg) 1010de2362d3Smrg{ 1011de2362d3Smrg 1012de2362d3Smrg} 1013de2362d3Smrg 1014de2362d3Smrgstatic void 1015de2362d3Smrgdrmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y) 1016de2362d3Smrg{ 1017de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 10188bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 1019de2362d3Smrg 10208bf5c682Smrg#if XF86_CRTC_VERSION < 7 102118781e08Smrg if (crtc->driverIsPerformingTransform) { 102218781e08Smrg x += crtc->x; 102318781e08Smrg y += crtc->y; 102418781e08Smrg xf86CrtcTransformCursorPos(crtc, &x, &y); 102518781e08Smrg } 102618781e08Smrg#endif 102718781e08Smrg 1028446f62d6Smrg drmmode_crtc->cursor_x = x; 1029446f62d6Smrg drmmode_crtc->cursor_y = y; 1030446f62d6Smrg 10318bf5c682Smrg drmModeMoveCursor(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); 1032de2362d3Smrg} 1033de2362d3Smrg 10348bf5c682Smrg#if XF86_CRTC_VERSION < 7 103518781e08Smrg 103618781e08Smrgstatic int 103718781e08Smrgdrmmode_cursor_src_offset(Rotation rotation, int width, int height, 103818781e08Smrg int x_dst, int y_dst) 103918781e08Smrg{ 104018781e08Smrg int t; 104118781e08Smrg 104218781e08Smrg switch (rotation & 0xf) { 104318781e08Smrg case RR_Rotate_90: 104418781e08Smrg t = x_dst; 104518781e08Smrg x_dst = height - y_dst - 1; 104618781e08Smrg y_dst = t; 104718781e08Smrg break; 104818781e08Smrg case RR_Rotate_180: 104918781e08Smrg x_dst = width - x_dst - 1; 105018781e08Smrg y_dst = height - y_dst - 1; 105118781e08Smrg break; 105218781e08Smrg case RR_Rotate_270: 105318781e08Smrg t = x_dst; 105418781e08Smrg x_dst = y_dst; 105518781e08Smrg y_dst = width - t - 1; 105618781e08Smrg break; 105718781e08Smrg } 105818781e08Smrg 105918781e08Smrg if (rotation & RR_Reflect_X) 106018781e08Smrg x_dst = width - x_dst - 1; 106118781e08Smrg if (rotation & RR_Reflect_Y) 106218781e08Smrg y_dst = height - y_dst - 1; 106318781e08Smrg 106418781e08Smrg return y_dst * height + x_dst; 106518781e08Smrg} 106618781e08Smrg 106718781e08Smrg#endif 106818781e08Smrg 1069446f62d6Smrgstatic Bool 1070446f62d6Smrgdrmmode_cursor_pixel(xf86CrtcPtr crtc, uint32_t *argb, Bool *premultiplied, 1071446f62d6Smrg Bool *apply_gamma) 10728bf5c682Smrg{ 1073446f62d6Smrg uint32_t alpha = *argb >> 24; 10748bf5c682Smrg uint32_t rgb[3]; 10758bf5c682Smrg int i; 10768bf5c682Smrg 1077446f62d6Smrg if (premultiplied) { 1078446f62d6Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1, 18, 4, 0, 0) 1079446f62d6Smrg if (alpha == 0 && (*argb & 0xffffff) != 0) { 1080446f62d6Smrg /* Doesn't look like premultiplied alpha */ 1081446f62d6Smrg *premultiplied = FALSE; 1082446f62d6Smrg return FALSE; 1083446f62d6Smrg } 1084446f62d6Smrg#endif 10858bf5c682Smrg 1086446f62d6Smrg if (!(*apply_gamma)) 1087446f62d6Smrg return TRUE; 1088446f62d6Smrg 1089446f62d6Smrg if (*argb > (alpha | alpha << 8 | alpha << 16 | alpha << 24)) { 1090446f62d6Smrg /* Un-premultiplied R/G/B would overflow gamma LUT, 1091446f62d6Smrg * don't apply gamma correction 1092446f62d6Smrg */ 1093446f62d6Smrg *apply_gamma = FALSE; 1094446f62d6Smrg return FALSE; 1095446f62d6Smrg } 1096446f62d6Smrg } 1097446f62d6Smrg 1098446f62d6Smrg if (!alpha) { 1099446f62d6Smrg *argb = 0; 1100446f62d6Smrg return TRUE; 1101446f62d6Smrg } 11028bf5c682Smrg 1103446f62d6Smrg /* Extract RGB */ 11048bf5c682Smrg for (i = 0; i < 3; i++) 1105446f62d6Smrg rgb[i] = (*argb >> (i * 8)) & 0xff; 1106446f62d6Smrg 1107446f62d6Smrg if (premultiplied) { 1108446f62d6Smrg /* Un-premultiply alpha */ 1109446f62d6Smrg for (i = 0; i < 3; i++) 1110446f62d6Smrg rgb[i] = rgb[i] * 0xff / alpha; 1111446f62d6Smrg } 11128bf5c682Smrg 1113446f62d6Smrg if (*apply_gamma) { 1114446f62d6Smrg rgb[0] = crtc->gamma_blue[rgb[0]] >> 8; 1115446f62d6Smrg rgb[1] = crtc->gamma_green[rgb[1]] >> 8; 1116446f62d6Smrg rgb[2] = crtc->gamma_red[rgb[2]] >> 8; 1117446f62d6Smrg } 11188bf5c682Smrg 1119446f62d6Smrg /* Premultiply alpha */ 1120446f62d6Smrg for (i = 0; i < 3; i++) 1121446f62d6Smrg rgb[i] = rgb[i] * alpha / 0xff; 1122446f62d6Smrg 1123446f62d6Smrg *argb = alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0]; 1124446f62d6Smrg return TRUE; 11258bf5c682Smrg} 11268bf5c682Smrg 1127de2362d3Smrgstatic void 1128de2362d3Smrgdrmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image) 1129de2362d3Smrg{ 113018781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 113118781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1132de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1133446f62d6Smrg unsigned id = drmmode_crtc->cursor_id; 1134446f62d6Smrg Bool premultiplied = TRUE; 1135446f62d6Smrg Bool apply_gamma = TRUE; 1136446f62d6Smrg uint32_t argb; 1137de2362d3Smrg uint32_t *ptr; 1138de2362d3Smrg 1139446f62d6Smrg if (drmmode_crtc->cursor && 1140446f62d6Smrg XF86_CRTC_CONFIG_PTR(pScrn)->cursor != drmmode_crtc->cursor) 1141446f62d6Smrg id ^= 1; 1142446f62d6Smrg 1143de2362d3Smrg /* cursor should be mapped already */ 1144446f62d6Smrg ptr = (uint32_t *)(drmmode_crtc->cursor_bo[id]->ptr); 1145446f62d6Smrg 1146446f62d6Smrg if (crtc->scrn->depth != 24 && crtc->scrn->depth != 32) 1147446f62d6Smrg apply_gamma = FALSE; 1148de2362d3Smrg 11498bf5c682Smrg#if XF86_CRTC_VERSION < 7 115018781e08Smrg if (crtc->driverIsPerformingTransform) { 115118781e08Smrg uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h; 115218781e08Smrg int dstx, dsty; 115318781e08Smrg int srcoffset; 115418781e08Smrg 1155446f62d6Smrgretry_transform: 115618781e08Smrg for (dsty = 0; dsty < cursor_h; dsty++) { 115718781e08Smrg for (dstx = 0; dstx < cursor_w; dstx++) { 115818781e08Smrg srcoffset = drmmode_cursor_src_offset(crtc->rotation, 115918781e08Smrg cursor_w, 116018781e08Smrg cursor_h, 116118781e08Smrg dstx, dsty); 1162446f62d6Smrg argb = image[srcoffset]; 1163446f62d6Smrg if (!drmmode_cursor_pixel(crtc, &argb, &premultiplied, 1164446f62d6Smrg &apply_gamma)) 1165446f62d6Smrg goto retry_transform; 116618781e08Smrg 1167446f62d6Smrg ptr[dsty * info->cursor_w + dstx] = cpu_to_le32(argb); 116818781e08Smrg } 116918781e08Smrg } 117018781e08Smrg } else 117118781e08Smrg#endif 117218781e08Smrg { 117318781e08Smrg uint32_t cursor_size = info->cursor_w * info->cursor_h; 117418781e08Smrg int i; 117518781e08Smrg 1176446f62d6Smrgretry: 1177446f62d6Smrg for (i = 0; i < cursor_size; i++) { 1178446f62d6Smrg argb = image[i]; 1179446f62d6Smrg if (!drmmode_cursor_pixel(crtc, &argb, &premultiplied, 1180446f62d6Smrg &apply_gamma)) 1181446f62d6Smrg goto retry; 1182446f62d6Smrg 1183446f62d6Smrg ptr[i] = cpu_to_le32(argb); 1184446f62d6Smrg } 1185446f62d6Smrg } 1186446f62d6Smrg 1187446f62d6Smrg if (id != drmmode_crtc->cursor_id) { 1188446f62d6Smrg drmmode_crtc->cursor_id = id; 1189446f62d6Smrg crtc->funcs->show_cursor(crtc); 119018781e08Smrg } 1191de2362d3Smrg} 1192de2362d3Smrg 119318781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 119418781e08Smrg 119518781e08Smrgstatic Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image) 119618781e08Smrg{ 119718781e08Smrg if (!drmmode_can_use_hw_cursor(crtc)) 119818781e08Smrg return FALSE; 119918781e08Smrg 120018781e08Smrg drmmode_load_cursor_argb(crtc, image); 120118781e08Smrg return TRUE; 120218781e08Smrg} 120318781e08Smrg 120418781e08Smrg#endif 1205de2362d3Smrg 1206de2362d3Smrgstatic void 1207de2362d3Smrgdrmmode_hide_cursor (xf86CrtcPtr crtc) 1208de2362d3Smrg{ 120918781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 121018781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1211de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 12128bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 1213de2362d3Smrg 12148bf5c682Smrg drmModeSetCursor(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 121518781e08Smrg info->cursor_w, info->cursor_h); 1216446f62d6Smrg drmmode_crtc->cursor = NULL; 1217de2362d3Smrg} 1218de2362d3Smrg 1219de2362d3Smrgstatic void 1220de2362d3Smrgdrmmode_show_cursor (xf86CrtcPtr crtc) 1221de2362d3Smrg{ 122218781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 122318781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1224de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 12258bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 1226446f62d6Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1227446f62d6Smrg CursorPtr cursor = xf86_config->cursor; 1228446f62d6Smrg int xhot = cursor->bits->xhot; 1229446f62d6Smrg int yhot = cursor->bits->yhot; 123018781e08Smrg static Bool use_set_cursor2 = TRUE; 1231446f62d6Smrg struct drm_mode_cursor2 arg; 1232446f62d6Smrg 1233446f62d6Smrg drmmode_crtc->cursor = xf86_config->cursor; 1234446f62d6Smrg 1235446f62d6Smrg memset(&arg, 0, sizeof(arg)); 1236446f62d6Smrg 1237446f62d6Smrg arg.handle = drmmode_crtc->cursor_bo[drmmode_crtc->cursor_id]->handle; 1238446f62d6Smrg arg.flags = DRM_MODE_CURSOR_BO; 1239446f62d6Smrg arg.crtc_id = drmmode_crtc->mode_crtc->crtc_id; 1240446f62d6Smrg arg.width = info->cursor_w; 1241446f62d6Smrg arg.height = info->cursor_h; 1242446f62d6Smrg 1243446f62d6Smrg if (crtc->rotation != RR_Rotate_0 && 1244446f62d6Smrg crtc->rotation != (RR_Rotate_180 | RR_Reflect_X | 1245446f62d6Smrg RR_Reflect_Y)) { 1246446f62d6Smrg int t; 1247446f62d6Smrg 1248446f62d6Smrg /* Reflect & rotate hotspot position */ 1249446f62d6Smrg if (crtc->rotation & RR_Reflect_X) 1250446f62d6Smrg xhot = info->cursor_w - xhot - 1; 1251446f62d6Smrg if (crtc->rotation & RR_Reflect_Y) 1252446f62d6Smrg yhot = info->cursor_h - yhot - 1; 1253446f62d6Smrg 1254446f62d6Smrg switch (crtc->rotation & 0xf) { 1255446f62d6Smrg case RR_Rotate_90: 1256446f62d6Smrg t = xhot; 1257446f62d6Smrg xhot = yhot; 1258446f62d6Smrg yhot = info->cursor_w - t - 1; 1259446f62d6Smrg break; 1260446f62d6Smrg case RR_Rotate_180: 1261446f62d6Smrg xhot = info->cursor_w - xhot - 1; 1262446f62d6Smrg yhot = info->cursor_h - yhot - 1; 1263446f62d6Smrg break; 1264446f62d6Smrg case RR_Rotate_270: 1265446f62d6Smrg t = xhot; 1266446f62d6Smrg xhot = info->cursor_h - yhot - 1; 1267446f62d6Smrg yhot = t; 1268446f62d6Smrg } 1269446f62d6Smrg } 1270446f62d6Smrg 1271446f62d6Smrg if (xhot != drmmode_crtc->cursor_xhot || yhot != drmmode_crtc->cursor_yhot) { 1272446f62d6Smrg arg.flags |= DRM_MODE_CURSOR_MOVE; 1273446f62d6Smrg arg.x = drmmode_crtc->cursor_x += drmmode_crtc->cursor_xhot - xhot; 1274446f62d6Smrg arg.y = drmmode_crtc->cursor_y += drmmode_crtc->cursor_yhot - yhot; 1275446f62d6Smrg drmmode_crtc->cursor_xhot = xhot; 1276446f62d6Smrg drmmode_crtc->cursor_yhot = yhot; 1277446f62d6Smrg } 127818781e08Smrg 127918781e08Smrg if (use_set_cursor2) { 128018781e08Smrg int ret; 128118781e08Smrg 1282446f62d6Smrg arg.hot_x = xhot; 1283446f62d6Smrg arg.hot_y = yhot; 12847314432eSmrg 1285446f62d6Smrg ret = drmIoctl(pRADEONEnt->fd, DRM_IOCTL_MODE_CURSOR2, &arg); 1286cd2eb4f7Smrg if (ret == -1 && errno == EINVAL) 128718781e08Smrg use_set_cursor2 = FALSE; 128818781e08Smrg else 128918781e08Smrg return; 129018781e08Smrg } 129118781e08Smrg 1292446f62d6Smrg drmIoctl(pRADEONEnt->fd, DRM_IOCTL_MODE_CURSOR, &arg); 1293de2362d3Smrg} 1294de2362d3Smrg 12953ed65abbSmrg/* Xorg expects a non-NULL return value from drmmode_crtc_shadow_allocate, and 12963ed65abbSmrg * passes that back to drmmode_crtc_scanout_create; it doesn't use it for 12973ed65abbSmrg * anything else. 12983ed65abbSmrg */ 1299de2362d3Smrgstatic void * 1300de2362d3Smrgdrmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 1301de2362d3Smrg{ 1302de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 13037821949aSmrg 13043ed65abbSmrg if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 13053ed65abbSmrg height)) 13063ed65abbSmrg return NULL; 13073ed65abbSmrg 13083ed65abbSmrg return (void*)~0UL; 1309de2362d3Smrg} 1310de2362d3Smrg 1311de2362d3Smrgstatic PixmapPtr 1312de2362d3Smrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 1313de2362d3Smrg{ 1314de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1315de2362d3Smrg 13163ed65abbSmrg if (!data) { 13173ed65abbSmrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 13183ed65abbSmrg height); 13193ed65abbSmrg } 13203ed65abbSmrg 13213ed65abbSmrg return drmmode_crtc->rotate.pixmap; 1322de2362d3Smrg} 1323de2362d3Smrg 1324de2362d3Smrgstatic void 13257821949aSmrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) 1326de2362d3Smrg{ 1327de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1328de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 1329de2362d3Smrg 133018781e08Smrg drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate); 13317821949aSmrg} 1332de2362d3Smrg 13337821949aSmrgstatic void 13347821949aSmrgdrmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 13357821949aSmrg uint16_t *blue, int size) 13367821949aSmrg{ 13378bf5c682Smrg ScrnInfoPtr scrn = crtc->scrn; 13388bf5c682Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 13398bf5c682Smrg RADEONInfoPtr info = RADEONPTR(scrn); 13408bf5c682Smrg int i; 13418bf5c682Smrg 13428bf5c682Smrg drmmode_crtc_gamma_do_set(crtc, red, green, blue, size); 13438bf5c682Smrg 13448bf5c682Smrg /* Compute index of this CRTC into xf86_config->crtc */ 13458bf5c682Smrg for (i = 0; xf86_config->crtc[i] != crtc; i++) {} 13468bf5c682Smrg 13478bf5c682Smrg if (info->hwcursor_disabled & (1 << i)) 13488bf5c682Smrg return; 13497314432eSmrg 13508bf5c682Smrg#ifdef HAVE_XF86_CURSOR_RESET_CURSOR 13518bf5c682Smrg xf86CursorResetCursor(scrn->pScreen); 13528bf5c682Smrg#else 13538bf5c682Smrg xf86_reload_cursors(scrn->pScreen); 13548bf5c682Smrg#endif 135518781e08Smrg} 135618781e08Smrg 135718781e08Smrgstatic Bool 135818781e08Smrgdrmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) 135918781e08Smrg{ 136018781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 13613ed65abbSmrg unsigned scanout_id = drmmode_crtc->scanout_id; 136218781e08Smrg ScreenPtr screen = crtc->scrn->pScreen; 136318781e08Smrg PixmapDirtyUpdatePtr dirty; 136418781e08Smrg 136518781e08Smrg xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 13668bf5c682Smrg if (radeon_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) { 1367cd2eb4f7Smrg PixmapStopDirtyTracking(dirty->src, dirty->secondary_dst); 13688bf5c682Smrg break; 13698bf5c682Smrg } 137018781e08Smrg } 137118781e08Smrg 1372446f62d6Smrg drmmode_crtc_scanout_free(crtc); 13738bf5c682Smrg drmmode_crtc->prime_scanout_pixmap = NULL; 13748bf5c682Smrg 137518781e08Smrg if (!ppix) 137618781e08Smrg return TRUE; 137718781e08Smrg 137818781e08Smrg if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0], 137918781e08Smrg ppix->drawable.width, 138018781e08Smrg ppix->drawable.height)) 138118781e08Smrg return FALSE; 138218781e08Smrg 13833ed65abbSmrg if (drmmode_crtc->tear_free && 138418781e08Smrg !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 138518781e08Smrg ppix->drawable.width, 138618781e08Smrg ppix->drawable.height)) { 1387446f62d6Smrg drmmode_crtc_scanout_free(crtc); 138818781e08Smrg return FALSE; 138918781e08Smrg } 139018781e08Smrg 13918bf5c682Smrg drmmode_crtc->prime_scanout_pixmap = ppix; 13928bf5c682Smrg 13938bf5c682Smrg#ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC 13948bf5c682Smrg PixmapStartDirtyTracking(&ppix->drawable, 13958bf5c682Smrg drmmode_crtc->scanout[scanout_id].pixmap, 13968bf5c682Smrg 0, 0, 0, 0, RR_Rotate_0); 13978bf5c682Smrg#elif defined(HAS_DIRTYTRACKING_ROTATION) 13983ed65abbSmrg PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 139918781e08Smrg 0, 0, 0, 0, RR_Rotate_0); 140018781e08Smrg#elif defined(HAS_DIRTYTRACKING2) 14013ed65abbSmrg PixmapStartDirtyTracking2(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 140218781e08Smrg 0, 0, 0, 0); 140318781e08Smrg#else 14043ed65abbSmrg PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 0, 0); 140518781e08Smrg#endif 140618781e08Smrg return TRUE; 1407de2362d3Smrg} 1408de2362d3Smrg 140918781e08Smrgstatic xf86CrtcFuncsRec drmmode_crtc_funcs = { 1410de2362d3Smrg .dpms = drmmode_crtc_dpms, 1411de2362d3Smrg .set_mode_major = drmmode_set_mode_major, 1412de2362d3Smrg .set_cursor_colors = drmmode_set_cursor_colors, 1413de2362d3Smrg .set_cursor_position = drmmode_set_cursor_position, 1414de2362d3Smrg .show_cursor = drmmode_show_cursor, 1415de2362d3Smrg .hide_cursor = drmmode_hide_cursor, 1416de2362d3Smrg .load_cursor_argb = drmmode_load_cursor_argb, 141718781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 141818781e08Smrg .load_cursor_argb_check = drmmode_load_cursor_argb_check, 141918781e08Smrg#endif 1420de2362d3Smrg 1421de2362d3Smrg .gamma_set = drmmode_crtc_gamma_set, 1422de2362d3Smrg .shadow_create = drmmode_crtc_shadow_create, 1423de2362d3Smrg .shadow_allocate = drmmode_crtc_shadow_allocate, 1424de2362d3Smrg .shadow_destroy = drmmode_crtc_shadow_destroy, 1425de2362d3Smrg .destroy = NULL, /* XXX */ 142618781e08Smrg .set_scanout_pixmap = drmmode_set_scanout_pixmap, 1427de2362d3Smrg}; 1428de2362d3Smrg 1429de2362d3Smrgint drmmode_get_crtc_id(xf86CrtcPtr crtc) 1430de2362d3Smrg{ 1431de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1432de2362d3Smrg return drmmode_crtc->hw_id; 1433de2362d3Smrg} 1434de2362d3Smrg 1435de2362d3Smrgvoid drmmode_crtc_hw_id(xf86CrtcPtr crtc) 1436de2362d3Smrg{ 1437de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 14388bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 1439de2362d3Smrg struct drm_radeon_info ginfo; 1440de2362d3Smrg int r; 1441de2362d3Smrg uint32_t tmp; 1442de2362d3Smrg 1443de2362d3Smrg memset(&ginfo, 0, sizeof(ginfo)); 1444de2362d3Smrg ginfo.request = 0x4; 1445de2362d3Smrg tmp = drmmode_crtc->mode_crtc->crtc_id; 1446de2362d3Smrg ginfo.value = (uintptr_t)&tmp; 14478bf5c682Smrg r = drmCommandWriteRead(pRADEONEnt->fd, DRM_RADEON_INFO, &ginfo, sizeof(ginfo)); 1448de2362d3Smrg if (r) { 1449de2362d3Smrg drmmode_crtc->hw_id = -1; 1450de2362d3Smrg return; 1451de2362d3Smrg } 1452de2362d3Smrg drmmode_crtc->hw_id = tmp; 1453de2362d3Smrg} 1454de2362d3Smrg 145518781e08Smrgstatic unsigned int 145618781e08Smrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num) 1457de2362d3Smrg{ 1458de2362d3Smrg xf86CrtcPtr crtc; 1459de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc; 146018781e08Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 14618bf5c682Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1462de2362d3Smrg 14638bf5c682Smrg crtc = xf86CrtcCreate(pScrn, &info->drmmode_crtc_funcs); 146439413783Smrg if (!crtc) 146518781e08Smrg return 0; 1466de2362d3Smrg 1467de2362d3Smrg drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); 14688bf5c682Smrg drmmode_crtc->mode_crtc = drmModeGetCrtc(pRADEONEnt->fd, mode_res->crtcs[num]); 1469de2362d3Smrg drmmode_crtc->drmmode = drmmode; 147018781e08Smrg drmmode_crtc->dpms_mode = DPMSModeOff; 1471de2362d3Smrg crtc->driver_private = drmmode_crtc; 1472de2362d3Smrg drmmode_crtc_hw_id(crtc); 1473de2362d3Smrg 147418781e08Smrg /* Mark num'th crtc as in use on this device. */ 147518781e08Smrg pRADEONEnt->assigned_crtcs |= (1 << num); 147618781e08Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 147718781e08Smrg "Allocated crtc nr. %d to this screen.\n", num); 147818781e08Smrg 147918781e08Smrg return 1; 1480de2362d3Smrg} 1481de2362d3Smrg 14828bf5c682Smrg/* 14838bf5c682Smrg * Update all of the property values for an output 14848bf5c682Smrg */ 14858bf5c682Smrgstatic void 14868bf5c682Smrgdrmmode_output_update_properties(xf86OutputPtr output) 14878bf5c682Smrg{ 14888bf5c682Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 14898bf5c682Smrg int i, j, k; 14908bf5c682Smrg int err; 14918bf5c682Smrg drmModeConnectorPtr koutput; 14928bf5c682Smrg 14938bf5c682Smrg /* Use the most recently fetched values from the kernel */ 14948bf5c682Smrg koutput = drmmode_output->mode_output; 14958bf5c682Smrg 14968bf5c682Smrg if (!koutput) 14978bf5c682Smrg return; 14988bf5c682Smrg 14998bf5c682Smrg for (i = 0; i < drmmode_output->num_props; i++) { 15008bf5c682Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 15018bf5c682Smrg 15028bf5c682Smrg for (j = 0; j < koutput->count_props; j++) { 15038bf5c682Smrg if (koutput->props[j] != p->mode_prop->prop_id) 15048bf5c682Smrg continue; 15058bf5c682Smrg 15068bf5c682Smrg /* Check to see if the property value has changed */ 15078bf5c682Smrg if (koutput->prop_values[j] == p->value) 15088bf5c682Smrg break; 15098bf5c682Smrg 15108bf5c682Smrg p->value = koutput->prop_values[j]; 15118bf5c682Smrg 15128bf5c682Smrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 15138bf5c682Smrg INT32 value = p->value; 15148bf5c682Smrg 15158bf5c682Smrg err = RRChangeOutputProperty(output->randr_output, 15168bf5c682Smrg p->atoms[0], XA_INTEGER, 15178bf5c682Smrg 32, PropModeReplace, 1, 15188bf5c682Smrg &value, FALSE, TRUE); 15198bf5c682Smrg if (err != 0) { 15208bf5c682Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 15218bf5c682Smrg "RRChangeOutputProperty error, %d\n", 15228bf5c682Smrg err); 15238bf5c682Smrg } 15248bf5c682Smrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 15258bf5c682Smrg for (k = 0; k < p->mode_prop->count_enums; k++) { 15268bf5c682Smrg if (p->mode_prop->enums[k].value == p->value) 15278bf5c682Smrg break; 15288bf5c682Smrg } 15298bf5c682Smrg if (k < p->mode_prop->count_enums) { 15308bf5c682Smrg err = RRChangeOutputProperty(output->randr_output, 15318bf5c682Smrg p->atoms[0], XA_ATOM, 15328bf5c682Smrg 32, PropModeReplace, 1, 15338bf5c682Smrg &p->atoms[k + 1], FALSE, 15348bf5c682Smrg TRUE); 15358bf5c682Smrg if (err != 0) { 15368bf5c682Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 15378bf5c682Smrg "RRChangeOutputProperty error, %d\n", 15388bf5c682Smrg err); 15398bf5c682Smrg } 15408bf5c682Smrg } 15418bf5c682Smrg } 15428bf5c682Smrg 15438bf5c682Smrg break; 15448bf5c682Smrg } 15458bf5c682Smrg } 15468bf5c682Smrg} 15478bf5c682Smrg 1548de2362d3Smrgstatic xf86OutputStatus 1549de2362d3Smrgdrmmode_output_detect(xf86OutputPtr output) 1550de2362d3Smrg{ 1551de2362d3Smrg /* go to the hw and retrieve a new output struct */ 1552de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 15538bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 1554de2362d3Smrg xf86OutputStatus status; 1555de2362d3Smrg drmModeFreeConnector(drmmode_output->mode_output); 1556de2362d3Smrg 15578bf5c682Smrg drmmode_output->mode_output = 15588bf5c682Smrg drmModeGetConnector(pRADEONEnt->fd, drmmode_output->output_id); 15598bf5c682Smrg if (!drmmode_output->mode_output) { 15608bf5c682Smrg drmmode_output->output_id = -1; 156118781e08Smrg return XF86OutputStatusDisconnected; 15628bf5c682Smrg } 15638bf5c682Smrg 15648bf5c682Smrg drmmode_output_update_properties(output); 1565de2362d3Smrg 1566de2362d3Smrg switch (drmmode_output->mode_output->connection) { 1567de2362d3Smrg case DRM_MODE_CONNECTED: 1568de2362d3Smrg status = XF86OutputStatusConnected; 1569de2362d3Smrg break; 1570de2362d3Smrg case DRM_MODE_DISCONNECTED: 1571de2362d3Smrg status = XF86OutputStatusDisconnected; 1572de2362d3Smrg break; 1573de2362d3Smrg default: 1574de2362d3Smrg case DRM_MODE_UNKNOWNCONNECTION: 1575de2362d3Smrg status = XF86OutputStatusUnknown; 1576de2362d3Smrg break; 1577de2362d3Smrg } 1578de2362d3Smrg return status; 1579de2362d3Smrg} 1580de2362d3Smrg 1581de2362d3Smrgstatic Bool 1582de2362d3Smrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) 1583de2362d3Smrg{ 1584de2362d3Smrg return MODE_OK; 1585de2362d3Smrg} 1586de2362d3Smrg 1587446f62d6Smrgstatic void 1588446f62d6Smrgdrmmode_output_attach_tile(xf86OutputPtr output) 1589446f62d6Smrg{ 1590446f62d6Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1, 17, 99, 901, 0) 1591446f62d6Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1592446f62d6Smrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 1593446f62d6Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 1594446f62d6Smrg struct xf86CrtcTileInfo tile_info, *set = NULL; 1595446f62d6Smrg int i; 1596446f62d6Smrg 1597446f62d6Smrg if (!koutput) { 1598446f62d6Smrg xf86OutputSetTile(output, NULL); 1599446f62d6Smrg return; 1600446f62d6Smrg } 1601446f62d6Smrg 1602446f62d6Smrg /* look for a TILE property */ 1603446f62d6Smrg for (i = 0; i < koutput->count_props; i++) { 1604446f62d6Smrg drmModePropertyPtr props; 1605446f62d6Smrg props = drmModeGetProperty(pRADEONEnt->fd, koutput->props[i]); 1606446f62d6Smrg if (!props) 1607446f62d6Smrg continue; 1608446f62d6Smrg 1609446f62d6Smrg if (!(props->flags & DRM_MODE_PROP_BLOB)) { 1610446f62d6Smrg drmModeFreeProperty(props); 1611446f62d6Smrg continue; 1612446f62d6Smrg } 1613446f62d6Smrg 1614446f62d6Smrg if (!strcmp(props->name, "TILE")) { 1615446f62d6Smrg drmModeFreePropertyBlob(drmmode_output->tile_blob); 1616446f62d6Smrg drmmode_output->tile_blob = 1617446f62d6Smrg drmModeGetPropertyBlob(pRADEONEnt->fd, 1618446f62d6Smrg koutput->prop_values[i]); 1619446f62d6Smrg } 1620446f62d6Smrg drmModeFreeProperty(props); 1621446f62d6Smrg } 1622446f62d6Smrg if (drmmode_output->tile_blob) { 1623446f62d6Smrg if (xf86OutputParseKMSTile(drmmode_output->tile_blob->data, 1624446f62d6Smrg drmmode_output->tile_blob->length, 1625446f62d6Smrg &tile_info) == TRUE) 1626446f62d6Smrg set = &tile_info; 1627446f62d6Smrg } 1628446f62d6Smrg xf86OutputSetTile(output, set); 1629446f62d6Smrg#endif 1630446f62d6Smrg} 1631446f62d6Smrg 16328bf5c682Smrgstatic int 16338bf5c682Smrgkoutput_get_prop_idx(int fd, drmModeConnectorPtr koutput, 16348bf5c682Smrg int type, const char *name) 16358bf5c682Smrg{ 16368bf5c682Smrg int idx = -1; 16378bf5c682Smrg 16388bf5c682Smrg for (int i = 0; i < koutput->count_props; i++) { 16398bf5c682Smrg drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]); 16408bf5c682Smrg 16418bf5c682Smrg if (!prop) 16428bf5c682Smrg continue; 16438bf5c682Smrg 16448bf5c682Smrg if (drm_property_type_is(prop, type) && !strcmp(prop->name, name)) 16458bf5c682Smrg idx = i; 16468bf5c682Smrg 16478bf5c682Smrg drmModeFreeProperty(prop); 16488bf5c682Smrg 16498bf5c682Smrg if (idx > -1) 16508bf5c682Smrg break; 16518bf5c682Smrg } 16528bf5c682Smrg 16538bf5c682Smrg return idx; 16548bf5c682Smrg} 16558bf5c682Smrg 16568bf5c682Smrgstatic int 16578bf5c682Smrgkoutput_get_prop_id(int fd, drmModeConnectorPtr koutput, 16588bf5c682Smrg int type, const char *name) 16598bf5c682Smrg{ 16608bf5c682Smrg int idx = koutput_get_prop_idx(fd, koutput, type, name); 16618bf5c682Smrg 16628bf5c682Smrg return (idx > -1) ? koutput->props[idx] : -1; 16638bf5c682Smrg} 16648bf5c682Smrg 16658bf5c682Smrgstatic drmModePropertyBlobPtr 16668bf5c682Smrgkoutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name) 16678bf5c682Smrg{ 16688bf5c682Smrg drmModePropertyBlobPtr blob = NULL; 16698bf5c682Smrg int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name); 16708bf5c682Smrg 16718bf5c682Smrg if (idx > -1) 16728bf5c682Smrg blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]); 16738bf5c682Smrg 16748bf5c682Smrg return blob; 16758bf5c682Smrg} 16768bf5c682Smrg 1677de2362d3Smrgstatic DisplayModePtr 1678de2362d3Smrgdrmmode_output_get_modes(xf86OutputPtr output) 1679de2362d3Smrg{ 1680de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1681de2362d3Smrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 16828bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 1683de2362d3Smrg int i; 1684de2362d3Smrg DisplayModePtr Modes = NULL, Mode; 1685de2362d3Smrg xf86MonPtr mon = NULL; 1686de2362d3Smrg 168718781e08Smrg if (!koutput) 168818781e08Smrg return NULL; 168918781e08Smrg 16908bf5c682Smrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 16918bf5c682Smrg 1692de2362d3Smrg /* look for an EDID property */ 16938bf5c682Smrg drmmode_output->edid_blob = 16948bf5c682Smrg koutput_get_prop_blob(pRADEONEnt->fd, koutput, "EDID"); 1695de2362d3Smrg 1696de2362d3Smrg if (drmmode_output->edid_blob) { 1697de2362d3Smrg mon = xf86InterpretEDID(output->scrn->scrnIndex, 1698de2362d3Smrg drmmode_output->edid_blob->data); 1699de2362d3Smrg if (mon && drmmode_output->edid_blob->length > 128) 1700de2362d3Smrg mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 1701de2362d3Smrg } 1702de2362d3Smrg xf86OutputSetEDID(output, mon); 1703de2362d3Smrg 1704446f62d6Smrg drmmode_output_attach_tile(output); 1705446f62d6Smrg 1706de2362d3Smrg /* modes should already be available */ 1707de2362d3Smrg for (i = 0; i < koutput->count_modes; i++) { 1708de2362d3Smrg Mode = xnfalloc(sizeof(DisplayModeRec)); 1709de2362d3Smrg 1710de2362d3Smrg drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode); 1711de2362d3Smrg Modes = xf86ModesAdd(Modes, Mode); 1712de2362d3Smrg 1713de2362d3Smrg } 1714de2362d3Smrg return Modes; 1715de2362d3Smrg} 1716de2362d3Smrg 1717de2362d3Smrgstatic void 1718de2362d3Smrgdrmmode_output_destroy(xf86OutputPtr output) 1719de2362d3Smrg{ 1720de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1721de2362d3Smrg int i; 1722de2362d3Smrg 1723446f62d6Smrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 1724446f62d6Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1, 17, 99, 901, 0) 1725446f62d6Smrg drmModeFreePropertyBlob(drmmode_output->tile_blob); 1726446f62d6Smrg#endif 1727446f62d6Smrg 1728de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 1729de2362d3Smrg drmModeFreeProperty(drmmode_output->props[i].mode_prop); 1730de2362d3Smrg free(drmmode_output->props[i].atoms); 1731de2362d3Smrg } 1732de2362d3Smrg for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) { 1733de2362d3Smrg drmModeFreeEncoder(drmmode_output->mode_encoders[i]); 1734de2362d3Smrg } 173518781e08Smrg free(drmmode_output->mode_encoders); 1736de2362d3Smrg free(drmmode_output->props); 1737de2362d3Smrg drmModeFreeConnector(drmmode_output->mode_output); 1738de2362d3Smrg free(drmmode_output); 1739de2362d3Smrg output->driver_private = NULL; 1740de2362d3Smrg} 1741de2362d3Smrg 1742de2362d3Smrgstatic void 1743de2362d3Smrgdrmmode_output_dpms(xf86OutputPtr output, int mode) 1744de2362d3Smrg{ 1745de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 174618781e08Smrg xf86CrtcPtr crtc = output->crtc; 1747de2362d3Smrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 17488bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 1749de2362d3Smrg 175018781e08Smrg if (!koutput) 175118781e08Smrg return; 175218781e08Smrg 17538bf5c682Smrg if (mode != DPMSModeOn && crtc) 175418781e08Smrg drmmode_do_crtc_dpms(crtc, mode); 175518781e08Smrg 17568bf5c682Smrg drmModeConnectorSetProperty(pRADEONEnt->fd, koutput->connector_id, 1757de2362d3Smrg drmmode_output->dpms_enum_id, mode); 175818781e08Smrg 175918781e08Smrg if (mode == DPMSModeOn && crtc) { 176018781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 176118781e08Smrg 176218781e08Smrg if (drmmode_crtc->need_modeset) 176318781e08Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x, 176418781e08Smrg crtc->y); 176518781e08Smrg else 176618781e08Smrg drmmode_do_crtc_dpms(crtc, mode); 176718781e08Smrg } 1768de2362d3Smrg} 1769de2362d3Smrg 1770de2362d3Smrg 1771de2362d3Smrgstatic Bool 1772de2362d3Smrgdrmmode_property_ignore(drmModePropertyPtr prop) 1773de2362d3Smrg{ 1774de2362d3Smrg if (!prop) 1775de2362d3Smrg return TRUE; 1776de2362d3Smrg /* ignore blob prop */ 1777de2362d3Smrg if (prop->flags & DRM_MODE_PROP_BLOB) 1778de2362d3Smrg return TRUE; 1779de2362d3Smrg /* ignore standard property */ 1780de2362d3Smrg if (!strcmp(prop->name, "EDID") || 1781de2362d3Smrg !strcmp(prop->name, "DPMS")) 1782de2362d3Smrg return TRUE; 1783de2362d3Smrg 1784de2362d3Smrg return FALSE; 1785de2362d3Smrg} 1786de2362d3Smrg 1787de2362d3Smrgstatic void 1788de2362d3Smrgdrmmode_output_create_resources(xf86OutputPtr output) 1789de2362d3Smrg{ 17903ed65abbSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1791de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1792de2362d3Smrg drmModeConnectorPtr mode_output = drmmode_output->mode_output; 17938bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 17943ed65abbSmrg drmModePropertyPtr drmmode_prop, tearfree_prop; 1795de2362d3Smrg int i, j, err; 179639413783Smrg Atom name; 179739413783Smrg 179839413783Smrg /* Create CONNECTOR_ID property */ 179939413783Smrg name = MakeAtom("CONNECTOR_ID", 12, TRUE); 180039413783Smrg if (name != BAD_RESOURCE) { 180139413783Smrg INT32 value = mode_output->connector_id; 180239413783Smrg 180339413783Smrg err = RRConfigureOutputProperty(output->randr_output, name, 180439413783Smrg FALSE, FALSE, TRUE, 1, &value); 180539413783Smrg if (err != Success) { 180639413783Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 180739413783Smrg "RRConfigureOutputProperty error, %d\n", err); 180839413783Smrg } 180939413783Smrg 181039413783Smrg err = RRChangeOutputProperty(output->randr_output, name, 181139413783Smrg XA_INTEGER, 32, PropModeReplace, 1, 181239413783Smrg &value, FALSE, FALSE); 181339413783Smrg if (err != Success) { 181439413783Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 181539413783Smrg "RRChangeOutputProperty error, %d\n", err); 181639413783Smrg } 181739413783Smrg } 1818de2362d3Smrg 18193ed65abbSmrg drmmode_output->props = calloc(mode_output->count_props + 1, sizeof(drmmode_prop_rec)); 1820de2362d3Smrg if (!drmmode_output->props) 1821de2362d3Smrg return; 1822de2362d3Smrg 1823de2362d3Smrg drmmode_output->num_props = 0; 1824de2362d3Smrg for (i = 0, j = 0; i < mode_output->count_props; i++) { 18258bf5c682Smrg drmmode_prop = drmModeGetProperty(pRADEONEnt->fd, mode_output->props[i]); 1826de2362d3Smrg if (drmmode_property_ignore(drmmode_prop)) { 1827de2362d3Smrg drmModeFreeProperty(drmmode_prop); 1828de2362d3Smrg continue; 1829de2362d3Smrg } 1830de2362d3Smrg drmmode_output->props[j].mode_prop = drmmode_prop; 1831de2362d3Smrg drmmode_output->props[j].value = mode_output->prop_values[i]; 1832de2362d3Smrg drmmode_output->num_props++; 1833de2362d3Smrg j++; 1834de2362d3Smrg } 1835de2362d3Smrg 18363ed65abbSmrg /* Userspace-only property for TearFree */ 18373ed65abbSmrg tearfree_prop = calloc(1, sizeof(*tearfree_prop)); 18383ed65abbSmrg tearfree_prop->flags = DRM_MODE_PROP_ENUM; 183939413783Smrg strcpy(tearfree_prop->name, "TearFree"); 18403ed65abbSmrg tearfree_prop->count_enums = 3; 18413ed65abbSmrg tearfree_prop->enums = calloc(tearfree_prop->count_enums, 18423ed65abbSmrg sizeof(*tearfree_prop->enums)); 184339413783Smrg strcpy(tearfree_prop->enums[0].name, "off"); 184439413783Smrg strcpy(tearfree_prop->enums[1].name, "on"); 18453ed65abbSmrg tearfree_prop->enums[1].value = 1; 184639413783Smrg strcpy(tearfree_prop->enums[2].name, "auto"); 18473ed65abbSmrg tearfree_prop->enums[2].value = 2; 18483ed65abbSmrg drmmode_output->props[j].mode_prop = tearfree_prop; 18493ed65abbSmrg drmmode_output->props[j].value = info->tear_free; 18503ed65abbSmrg drmmode_output->tear_free = info->tear_free; 18513ed65abbSmrg drmmode_output->num_props++; 18523ed65abbSmrg 1853de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 1854de2362d3Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 1855de2362d3Smrg drmmode_prop = p->mode_prop; 1856de2362d3Smrg 1857de2362d3Smrg if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 1858de2362d3Smrg INT32 range[2]; 1859de2362d3Smrg INT32 value = p->value; 1860de2362d3Smrg 1861de2362d3Smrg p->num_atoms = 1; 1862de2362d3Smrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 1863de2362d3Smrg if (!p->atoms) 1864de2362d3Smrg continue; 1865de2362d3Smrg p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 1866de2362d3Smrg range[0] = drmmode_prop->values[0]; 1867de2362d3Smrg range[1] = drmmode_prop->values[1]; 1868de2362d3Smrg err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 1869de2362d3Smrg FALSE, TRUE, 1870de2362d3Smrg drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 1871de2362d3Smrg 2, range); 1872de2362d3Smrg if (err != 0) { 1873de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1874de2362d3Smrg "RRConfigureOutputProperty error, %d\n", err); 1875de2362d3Smrg } 1876de2362d3Smrg err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 1877de2362d3Smrg XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, TRUE); 1878de2362d3Smrg if (err != 0) { 1879de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1880de2362d3Smrg "RRChangeOutputProperty error, %d\n", err); 1881de2362d3Smrg } 1882de2362d3Smrg } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 1883de2362d3Smrg p->num_atoms = drmmode_prop->count_enums + 1; 1884de2362d3Smrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 1885de2362d3Smrg if (!p->atoms) 1886de2362d3Smrg continue; 1887de2362d3Smrg p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 1888de2362d3Smrg for (j = 1; j <= drmmode_prop->count_enums; j++) { 1889de2362d3Smrg struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; 1890de2362d3Smrg p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); 1891de2362d3Smrg } 1892de2362d3Smrg err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 1893de2362d3Smrg FALSE, FALSE, 1894de2362d3Smrg drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 1895de2362d3Smrg p->num_atoms - 1, (INT32 *)&p->atoms[1]); 1896de2362d3Smrg if (err != 0) { 1897de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1898de2362d3Smrg "RRConfigureOutputProperty error, %d\n", err); 1899de2362d3Smrg } 1900de2362d3Smrg for (j = 0; j < drmmode_prop->count_enums; j++) 1901de2362d3Smrg if (drmmode_prop->enums[j].value == p->value) 1902de2362d3Smrg break; 1903de2362d3Smrg /* there's always a matching value */ 1904de2362d3Smrg err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 1905de2362d3Smrg XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE); 1906de2362d3Smrg if (err != 0) { 1907de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1908de2362d3Smrg "RRChangeOutputProperty error, %d\n", err); 1909de2362d3Smrg } 1910de2362d3Smrg } 1911de2362d3Smrg } 1912de2362d3Smrg} 1913de2362d3Smrg 191439413783Smrgstatic void 191539413783Smrgdrmmode_output_set_tear_free(RADEONEntPtr pRADEONEnt, 191639413783Smrg drmmode_output_private_ptr drmmode_output, 191739413783Smrg xf86CrtcPtr crtc, int tear_free) 191839413783Smrg{ 191939413783Smrg if (drmmode_output->tear_free == tear_free) 192039413783Smrg return; 192139413783Smrg 192239413783Smrg drmmode_output->tear_free = tear_free; 192339413783Smrg 192439413783Smrg if (crtc) { 192539413783Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 192639413783Smrg crtc->x, crtc->y); 192739413783Smrg } 192839413783Smrg} 192939413783Smrg 1930de2362d3Smrgstatic Bool 1931de2362d3Smrgdrmmode_output_set_property(xf86OutputPtr output, Atom property, 1932de2362d3Smrg RRPropertyValuePtr value) 1933de2362d3Smrg{ 1934de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 19358bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn); 1936de2362d3Smrg int i; 1937de2362d3Smrg 1938de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 1939de2362d3Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 1940de2362d3Smrg 1941de2362d3Smrg if (p->atoms[0] != property) 1942de2362d3Smrg continue; 1943de2362d3Smrg 1944de2362d3Smrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 1945de2362d3Smrg uint32_t val; 1946de2362d3Smrg 1947de2362d3Smrg if (value->type != XA_INTEGER || value->format != 32 || 1948de2362d3Smrg value->size != 1) 1949de2362d3Smrg return FALSE; 1950de2362d3Smrg val = *(uint32_t *)value->data; 1951de2362d3Smrg 19528bf5c682Smrg drmModeConnectorSetProperty(pRADEONEnt->fd, drmmode_output->output_id, 1953de2362d3Smrg p->mode_prop->prop_id, (uint64_t)val); 1954de2362d3Smrg return TRUE; 1955de2362d3Smrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 1956de2362d3Smrg Atom atom; 1957de2362d3Smrg const char *name; 1958de2362d3Smrg int j; 1959de2362d3Smrg 1960de2362d3Smrg if (value->type != XA_ATOM || value->format != 32 || value->size != 1) 1961de2362d3Smrg return FALSE; 1962de2362d3Smrg memcpy(&atom, value->data, 4); 19638bf5c682Smrg if (!(name = NameForAtom(atom))) 19648bf5c682Smrg return FALSE; 1965de2362d3Smrg 1966de2362d3Smrg /* search for matching name string, then set its value down */ 1967de2362d3Smrg for (j = 0; j < p->mode_prop->count_enums; j++) { 1968de2362d3Smrg if (!strcmp(p->mode_prop->enums[j].name, name)) { 19693ed65abbSmrg if (i == (drmmode_output->num_props - 1)) { 197039413783Smrg drmmode_output_set_tear_free(pRADEONEnt, drmmode_output, 197139413783Smrg output->crtc, j); 19723ed65abbSmrg } else { 19738bf5c682Smrg drmModeConnectorSetProperty(pRADEONEnt->fd, 19743ed65abbSmrg drmmode_output->output_id, 19753ed65abbSmrg p->mode_prop->prop_id, 19763ed65abbSmrg p->mode_prop->enums[j].value); 19773ed65abbSmrg } 19783ed65abbSmrg 1979de2362d3Smrg return TRUE; 1980de2362d3Smrg } 1981de2362d3Smrg } 1982de2362d3Smrg } 1983de2362d3Smrg } 1984de2362d3Smrg 1985de2362d3Smrg return TRUE; 1986de2362d3Smrg} 1987de2362d3Smrg 1988de2362d3Smrgstatic Bool 1989de2362d3Smrgdrmmode_output_get_property(xf86OutputPtr output, Atom property) 1990de2362d3Smrg{ 1991de2362d3Smrg return TRUE; 1992de2362d3Smrg} 1993de2362d3Smrg 1994de2362d3Smrgstatic const xf86OutputFuncsRec drmmode_output_funcs = { 1995de2362d3Smrg .dpms = drmmode_output_dpms, 1996de2362d3Smrg .create_resources = drmmode_output_create_resources, 1997de2362d3Smrg .set_property = drmmode_output_set_property, 1998de2362d3Smrg .get_property = drmmode_output_get_property, 1999de2362d3Smrg .detect = drmmode_output_detect, 2000de2362d3Smrg .mode_valid = drmmode_output_mode_valid, 2001de2362d3Smrg 2002de2362d3Smrg .get_modes = drmmode_output_get_modes, 2003de2362d3Smrg .destroy = drmmode_output_destroy 2004de2362d3Smrg}; 2005de2362d3Smrg 2006de2362d3Smrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown, 2007de2362d3Smrg SubPixelHorizontalRGB, 2008de2362d3Smrg SubPixelHorizontalBGR, 2009de2362d3Smrg SubPixelVerticalRGB, 2010de2362d3Smrg SubPixelVerticalBGR, 2011de2362d3Smrg SubPixelNone }; 2012de2362d3Smrg 2013de2362d3Smrgconst char *output_names[] = { "None", 2014de2362d3Smrg "VGA", 2015de2362d3Smrg "DVI", 2016de2362d3Smrg "DVI", 2017de2362d3Smrg "DVI", 2018de2362d3Smrg "Composite", 2019de2362d3Smrg "S-video", 2020de2362d3Smrg "LVDS", 2021de2362d3Smrg "CTV", 2022de2362d3Smrg "DIN", 2023de2362d3Smrg "DisplayPort", 2024de2362d3Smrg "HDMI", 2025de2362d3Smrg "HDMI", 2026de2362d3Smrg "TV", 2027de2362d3Smrg "eDP" 2028de2362d3Smrg}; 2029de2362d3Smrg 203018781e08Smrg#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0])) 203118781e08Smrg 203218781e08Smrgstatic xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id) 203318781e08Smrg{ 203418781e08Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 203518781e08Smrg int i; 203618781e08Smrg for (i = 0; i < xf86_config->num_output; i++) { 203718781e08Smrg xf86OutputPtr output = xf86_config->output[i]; 203818781e08Smrg drmmode_output_private_ptr drmmode_output; 203918781e08Smrg 204018781e08Smrg drmmode_output = output->driver_private; 204118781e08Smrg if (drmmode_output->output_id == id) 204218781e08Smrg return output; 204318781e08Smrg } 204418781e08Smrg return NULL; 204518781e08Smrg} 204618781e08Smrg 204718781e08Smrgstatic int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path) 204818781e08Smrg{ 204918781e08Smrg char *conn; 205018781e08Smrg char conn_id[5]; 205118781e08Smrg int id, len; 205218781e08Smrg char *blob_data; 205318781e08Smrg 205418781e08Smrg if (!path_blob) 205518781e08Smrg return -1; 205618781e08Smrg 205718781e08Smrg blob_data = path_blob->data; 205818781e08Smrg /* we only handle MST paths for now */ 205918781e08Smrg if (strncmp(blob_data, "mst:", 4)) 206018781e08Smrg return -1; 206118781e08Smrg 206218781e08Smrg conn = strchr(blob_data + 4, '-'); 206318781e08Smrg if (!conn) 206418781e08Smrg return -1; 206518781e08Smrg len = conn - (blob_data + 4); 206618781e08Smrg if (len + 1 > 5) 206718781e08Smrg return -1; 206818781e08Smrg memcpy(conn_id, blob_data + 4, len); 206918781e08Smrg conn_id[len] = '\0'; 207018781e08Smrg id = strtoul(conn_id, NULL, 10); 207118781e08Smrg 207218781e08Smrg *conn_base_id = id; 207318781e08Smrg 207418781e08Smrg *path = conn + 1; 207518781e08Smrg return 0; 207618781e08Smrg} 207718781e08Smrg 2078de2362d3Smrgstatic void 207918781e08Smrgdrmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name, 208018781e08Smrg drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi) 208118781e08Smrg{ 208218781e08Smrg xf86OutputPtr output; 208318781e08Smrg int conn_id; 208418781e08Smrg char *extra_path; 208518781e08Smrg 208618781e08Smrg output = NULL; 208718781e08Smrg if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0) 208818781e08Smrg output = find_output(pScrn, conn_id); 208918781e08Smrg if (output) { 209018781e08Smrg snprintf(name, 32, "%s-%s", output->name, extra_path); 209118781e08Smrg } else { 20928bf5c682Smrg if (koutput->connector_type >= NUM_OUTPUT_NAMES) { 209318781e08Smrg snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, 209418781e08Smrg koutput->connector_type_id - 1); 20958bf5c682Smrg } else if (pScrn->is_gpu) { 209618781e08Smrg snprintf(name, 32, "%s-%d-%d", 209718781e08Smrg output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, 209818781e08Smrg koutput->connector_type_id - 1); 20998bf5c682Smrg } else { 210018781e08Smrg /* need to do smart conversion here for compat with non-kms ATI driver */ 210118781e08Smrg if (koutput->connector_type_id == 1) { 210218781e08Smrg switch(koutput->connector_type) { 210318781e08Smrg case DRM_MODE_CONNECTOR_DVII: 210418781e08Smrg case DRM_MODE_CONNECTOR_DVID: 210518781e08Smrg case DRM_MODE_CONNECTOR_DVIA: 210618781e08Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi); 210718781e08Smrg (*num_dvi)++; 210818781e08Smrg break; 210918781e08Smrg case DRM_MODE_CONNECTOR_HDMIA: 211018781e08Smrg case DRM_MODE_CONNECTOR_HDMIB: 211118781e08Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi); 211218781e08Smrg (*num_hdmi)++; 211318781e08Smrg break; 211418781e08Smrg case DRM_MODE_CONNECTOR_VGA: 211518781e08Smrg case DRM_MODE_CONNECTOR_DisplayPort: 211618781e08Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], 211718781e08Smrg koutput->connector_type_id - 1); 211818781e08Smrg break; 211918781e08Smrg default: 212018781e08Smrg snprintf(name, 32, "%s", output_names[koutput->connector_type]); 212118781e08Smrg break; 212218781e08Smrg } 212318781e08Smrg } else { 212418781e08Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], 212518781e08Smrg koutput->connector_type_id - 1); 212618781e08Smrg } 212718781e08Smrg } 212818781e08Smrg } 212918781e08Smrg} 213018781e08Smrg 213118781e08Smrgstatic unsigned int 213218781e08Smrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic) 21330d16fef4Smrg{ 213418781e08Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 21358bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 2136de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 2137de2362d3Smrg xf86OutputPtr output; 2138de2362d3Smrg drmModeConnectorPtr koutput; 2139de2362d3Smrg drmModeEncoderPtr *kencoders = NULL; 2140de2362d3Smrg drmmode_output_private_ptr drmmode_output; 214118781e08Smrg drmModePropertyBlobPtr path_blob = NULL; 214239413783Smrg#if XF86_CRTC_VERSION >= 8 214339413783Smrg Bool nonDesktop = FALSE; 214439413783Smrg#endif 2145de2362d3Smrg char name[32]; 2146de2362d3Smrg int i; 2147de2362d3Smrg const char *s; 2148de2362d3Smrg 21498bf5c682Smrg koutput = drmModeGetConnector(pRADEONEnt->fd, mode_res->connectors[num]); 2150de2362d3Smrg if (!koutput) 215118781e08Smrg return 0; 215218781e08Smrg 21538bf5c682Smrg path_blob = koutput_get_prop_blob(pRADEONEnt->fd, koutput, "PATH"); 2154de2362d3Smrg 215539413783Smrg#if XF86_CRTC_VERSION >= 8 215639413783Smrg i = koutput_get_prop_idx(pRADEONEnt->fd, koutput, DRM_MODE_PROP_RANGE, 215739413783Smrg "non-desktop"); 215839413783Smrg if (i >= 0) 215939413783Smrg nonDesktop = koutput->prop_values[i] != 0; 216039413783Smrg#endif 216139413783Smrg 2162de2362d3Smrg kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); 2163de2362d3Smrg if (!kencoders) { 2164de2362d3Smrg goto out_free_encoders; 2165de2362d3Smrg } 2166de2362d3Smrg 2167de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) { 21688bf5c682Smrg kencoders[i] = drmModeGetEncoder(pRADEONEnt->fd, koutput->encoders[i]); 2169de2362d3Smrg if (!kencoders[i]) { 2170de2362d3Smrg goto out_free_encoders; 2171de2362d3Smrg } 2172de2362d3Smrg } 2173de2362d3Smrg 217418781e08Smrg drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi); 217518781e08Smrg if (path_blob) 217618781e08Smrg drmModeFreePropertyBlob(path_blob); 217718781e08Smrg 217818781e08Smrg if (path_blob && dynamic) { 217918781e08Smrg /* See if we have an output with this name already 218018781e08Smrg * and hook stuff up. 218118781e08Smrg */ 218218781e08Smrg for (i = 0; i < xf86_config->num_output; i++) { 218318781e08Smrg output = xf86_config->output[i]; 218418781e08Smrg 218518781e08Smrg if (strncmp(output->name, name, 32)) 218618781e08Smrg continue; 218718781e08Smrg 218818781e08Smrg drmmode_output = output->driver_private; 218918781e08Smrg drmmode_output->output_id = mode_res->connectors[num]; 219018781e08Smrg drmmode_output->mode_output = koutput; 219139413783Smrg#if XF86_CRTC_VERSION >= 8 219239413783Smrg output->non_desktop = nonDesktop; 219339413783Smrg#endif 219418781e08Smrg for (i = 0; i < koutput->count_encoders; i++) 219518781e08Smrg drmModeFreeEncoder(kencoders[i]); 219618781e08Smrg free(kencoders); 219718781e08Smrg return 0; 219818781e08Smrg } 2199de2362d3Smrg } 2200de2362d3Smrg 2201de2362d3Smrg if (xf86IsEntityShared(pScrn->entityList[0])) { 2202de2362d3Smrg if ((s = xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) { 2203de2362d3Smrg if (!RADEONZaphodStringMatches(pScrn, s, name)) 2204de2362d3Smrg goto out_free_encoders; 2205de2362d3Smrg } else { 2206446f62d6Smrg if (info->instance_id != num) 2207de2362d3Smrg goto out_free_encoders; 2208de2362d3Smrg } 2209de2362d3Smrg } 2210de2362d3Smrg 2211de2362d3Smrg output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name); 2212de2362d3Smrg if (!output) { 2213de2362d3Smrg goto out_free_encoders; 2214de2362d3Smrg } 2215de2362d3Smrg 2216de2362d3Smrg drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); 2217de2362d3Smrg if (!drmmode_output) { 2218de2362d3Smrg xf86OutputDestroy(output); 2219de2362d3Smrg goto out_free_encoders; 2220de2362d3Smrg } 2221de2362d3Smrg 222218781e08Smrg drmmode_output->output_id = mode_res->connectors[num]; 2223de2362d3Smrg drmmode_output->mode_output = koutput; 2224de2362d3Smrg drmmode_output->mode_encoders = kencoders; 2225de2362d3Smrg drmmode_output->drmmode = drmmode; 2226de2362d3Smrg output->mm_width = koutput->mmWidth; 2227de2362d3Smrg output->mm_height = koutput->mmHeight; 2228de2362d3Smrg 2229de2362d3Smrg output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 2230de2362d3Smrg output->interlaceAllowed = TRUE; 2231de2362d3Smrg output->doubleScanAllowed = TRUE; 2232de2362d3Smrg output->driver_private = drmmode_output; 223339413783Smrg#if XF86_CRTC_VERSION >= 8 223439413783Smrg output->non_desktop = nonDesktop; 223539413783Smrg#endif 2236de2362d3Smrg 2237de2362d3Smrg output->possible_crtcs = 0xffffffff; 2238de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) { 2239de2362d3Smrg output->possible_crtcs &= kencoders[i]->possible_crtcs; 2240de2362d3Smrg } 2241de2362d3Smrg /* work out the possible clones later */ 2242de2362d3Smrg output->possible_clones = 0; 2243de2362d3Smrg 22448bf5c682Smrg drmmode_output->dpms_enum_id = 22458bf5c682Smrg koutput_get_prop_id(pRADEONEnt->fd, koutput, DRM_MODE_PROP_ENUM, 22468bf5c682Smrg "DPMS"); 2247de2362d3Smrg 224818781e08Smrg if (dynamic) { 224918781e08Smrg output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output); 225018781e08Smrg drmmode_output_create_resources(output); 225118781e08Smrg } 225218781e08Smrg 225318781e08Smrg return 1; 2254de2362d3Smrgout_free_encoders: 2255de2362d3Smrg if (kencoders){ 2256de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) 2257de2362d3Smrg drmModeFreeEncoder(kencoders[i]); 2258de2362d3Smrg free(kencoders); 2259de2362d3Smrg } 2260de2362d3Smrg drmModeFreeConnector(koutput); 226118781e08Smrg return 0; 2262de2362d3Smrg} 2263de2362d3Smrg 2264de2362d3Smrguint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output) 2265de2362d3Smrg{ 2266de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private, clone_drmout; 2267de2362d3Smrg int i; 2268de2362d3Smrg xf86OutputPtr clone_output; 2269de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2270de2362d3Smrg int index_mask = 0; 2271de2362d3Smrg 2272de2362d3Smrg if (drmmode_output->enc_clone_mask == 0) 2273de2362d3Smrg return index_mask; 2274de2362d3Smrg 2275de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 2276de2362d3Smrg clone_output = xf86_config->output[i]; 2277de2362d3Smrg clone_drmout = clone_output->driver_private; 2278de2362d3Smrg if (output == clone_output) 2279de2362d3Smrg continue; 2280de2362d3Smrg 2281de2362d3Smrg if (clone_drmout->enc_mask == 0) 2282de2362d3Smrg continue; 2283de2362d3Smrg if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask) 2284de2362d3Smrg index_mask |= (1 << i); 2285de2362d3Smrg } 2286de2362d3Smrg return index_mask; 2287de2362d3Smrg} 2288de2362d3Smrg 2289de2362d3Smrg 2290de2362d3Smrgstatic void 229118781e08Smrgdrmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res) 2292de2362d3Smrg{ 2293de2362d3Smrg int i, j; 2294de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2295de2362d3Smrg 2296de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 2297de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 2298de2362d3Smrg drmmode_output_private_ptr drmmode_output; 2299de2362d3Smrg 2300de2362d3Smrg drmmode_output = output->driver_private; 2301de2362d3Smrg drmmode_output->enc_clone_mask = 0xff; 2302de2362d3Smrg /* and all the possible encoder clones for this output together */ 2303de2362d3Smrg for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) 2304de2362d3Smrg { 2305de2362d3Smrg int k; 230618781e08Smrg for (k = 0; k < mode_res->count_encoders; k++) { 230718781e08Smrg if (mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id) 2308de2362d3Smrg drmmode_output->enc_mask |= (1 << k); 2309de2362d3Smrg } 2310de2362d3Smrg 2311de2362d3Smrg drmmode_output->enc_clone_mask &= drmmode_output->mode_encoders[j]->possible_clones; 2312de2362d3Smrg } 2313de2362d3Smrg } 2314de2362d3Smrg 2315de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 2316de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 2317de2362d3Smrg output->possible_clones = find_clones(scrn, output); 2318de2362d3Smrg } 2319de2362d3Smrg} 2320de2362d3Smrg 2321de2362d3Smrg/* returns height alignment in pixels */ 2322de2362d3Smrgint drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling) 2323de2362d3Smrg{ 2324de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 2325de2362d3Smrg int height_align = 1; 2326de2362d3Smrg 2327de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 2328de2362d3Smrg if (tiling & RADEON_TILING_MACRO) 2329de2362d3Smrg height_align = info->num_channels * 8; 2330de2362d3Smrg else if (tiling & RADEON_TILING_MICRO) 2331de2362d3Smrg height_align = 8; 2332de2362d3Smrg else 2333de2362d3Smrg height_align = 8; 2334de2362d3Smrg } else { 233518781e08Smrg if (tiling & RADEON_TILING_MICRO_SQUARE) 233618781e08Smrg height_align = 32; 233718781e08Smrg else if (tiling) 2338de2362d3Smrg height_align = 16; 2339de2362d3Smrg else 2340de2362d3Smrg height_align = 1; 2341de2362d3Smrg } 2342de2362d3Smrg return height_align; 2343de2362d3Smrg} 2344de2362d3Smrg 2345de2362d3Smrg/* returns pitch alignment in pixels */ 2346de2362d3Smrgint drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling) 2347de2362d3Smrg{ 2348de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 2349de2362d3Smrg int pitch_align = 1; 2350de2362d3Smrg 2351de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 2352de2362d3Smrg if (tiling & RADEON_TILING_MACRO) { 2353de2362d3Smrg /* general surface requirements */ 2354de2362d3Smrg pitch_align = MAX(info->num_banks, 2355de2362d3Smrg (((info->group_bytes / 8) / bpe) * info->num_banks)) * 8; 2356de2362d3Smrg /* further restrictions for scanout */ 2357de2362d3Smrg pitch_align = MAX(info->num_banks * 8, pitch_align); 2358de2362d3Smrg } else if (tiling & RADEON_TILING_MICRO) { 2359de2362d3Smrg /* general surface requirements */ 2360de2362d3Smrg pitch_align = MAX(8, (info->group_bytes / (8 * bpe))); 2361de2362d3Smrg /* further restrictions for scanout */ 2362de2362d3Smrg pitch_align = MAX(info->group_bytes / bpe, pitch_align); 2363de2362d3Smrg } else { 2364de2362d3Smrg if (info->have_tiling_info) 2365de2362d3Smrg /* linear aligned requirements */ 2366de2362d3Smrg pitch_align = MAX(64, info->group_bytes / bpe); 2367de2362d3Smrg else 2368de2362d3Smrg /* default to 512 elements if we don't know the real 2369de2362d3Smrg * group size otherwise the kernel may reject the CS 2370de2362d3Smrg * if the group sizes don't match as the pitch won't 2371de2362d3Smrg * be aligned properly. 2372de2362d3Smrg */ 2373de2362d3Smrg pitch_align = 512; 2374de2362d3Smrg } 2375de2362d3Smrg } else { 2376de2362d3Smrg /* general surface requirements */ 2377de2362d3Smrg if (tiling) 2378de2362d3Smrg pitch_align = 256 / bpe; 2379de2362d3Smrg else 2380de2362d3Smrg pitch_align = 64; 2381de2362d3Smrg } 2382de2362d3Smrg return pitch_align; 2383de2362d3Smrg} 2384de2362d3Smrg 2385de2362d3Smrg/* returns base alignment in bytes */ 2386de2362d3Smrgint drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling) 2387de2362d3Smrg{ 2388de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 2389de2362d3Smrg int pixel_align = drmmode_get_pitch_align(scrn, bpe, tiling); 2390de2362d3Smrg int height_align = drmmode_get_height_align(scrn, tiling); 2391de2362d3Smrg int base_align = RADEON_GPU_PAGE_SIZE; 2392de2362d3Smrg 2393de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 2394de2362d3Smrg if (tiling & RADEON_TILING_MACRO) 2395de2362d3Smrg base_align = MAX(info->num_banks * info->num_channels * 8 * 8 * bpe, 2396de2362d3Smrg pixel_align * bpe * height_align); 2397de2362d3Smrg else { 2398de2362d3Smrg if (info->have_tiling_info) 2399de2362d3Smrg base_align = info->group_bytes; 2400de2362d3Smrg else 2401de2362d3Smrg /* default to 512 if we don't know the real 2402de2362d3Smrg * group size otherwise the kernel may reject the CS 2403de2362d3Smrg * if the group sizes don't match as the base won't 2404de2362d3Smrg * be aligned properly. 2405de2362d3Smrg */ 2406de2362d3Smrg base_align = 512; 2407de2362d3Smrg } 2408de2362d3Smrg } 2409de2362d3Smrg return base_align; 2410de2362d3Smrg} 2411de2362d3Smrg 2412de2362d3Smrgstatic Bool 2413de2362d3Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) 2414de2362d3Smrg{ 2415de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2416de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 241739413783Smrg struct radeon_buffer *old_front = NULL; 2418de2362d3Smrg ScreenPtr screen = xf86ScrnToScreen(scrn); 2419de2362d3Smrg int i, pitch, old_width, old_height, old_pitch; 242039413783Smrg int usage = CREATE_PIXMAP_USAGE_BACKING_PIXMAP; 242118781e08Smrg int cpp = info->pixel_bytes; 242239413783Smrg uint32_t tiling_flags; 2423de2362d3Smrg PixmapPtr ppix = screen->GetScreenPixmap(screen); 2424de2362d3Smrg void *fb_shadow; 2425de2362d3Smrg 2426de2362d3Smrg if (scrn->virtualX == width && scrn->virtualY == height) 2427de2362d3Smrg return TRUE; 2428de2362d3Smrg 242939413783Smrg if (width > xf86_config->maxWidth || height > xf86_config->maxHeight) { 243039413783Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 243139413783Smrg "Xorg tried resizing screen to %dx%d, but maximum " 243239413783Smrg "supported is %dx%d\n", width, height, 243339413783Smrg xf86_config->maxWidth, xf86_config->maxHeight); 243439413783Smrg return FALSE; 2435de2362d3Smrg } 2436de2362d3Smrg 243739413783Smrg if (info->allowColorTiling && !info->shadow_primary) { 243839413783Smrg if (info->ChipFamily < CHIP_FAMILY_R600 || info->allowColorTiling2D) 243939413783Smrg usage |= RADEON_CREATE_PIXMAP_TILING_MACRO; 244039413783Smrg else 244139413783Smrg usage |= RADEON_CREATE_PIXMAP_TILING_MICRO; 2442de2362d3Smrg } 2443de2362d3Smrg 244439413783Smrg xf86DrvMsg(scrn->scrnIndex, X_INFO, "Allocate new frame buffer %dx%d\n", 244539413783Smrg width, height); 2446de2362d3Smrg 2447de2362d3Smrg old_width = scrn->virtualX; 2448de2362d3Smrg old_height = scrn->virtualY; 2449de2362d3Smrg old_pitch = scrn->displayWidth; 245039413783Smrg old_front = info->front_buffer; 2451de2362d3Smrg 2452de2362d3Smrg scrn->virtualX = width; 2453de2362d3Smrg scrn->virtualY = height; 2454de2362d3Smrg 245539413783Smrg info->front_buffer = radeon_alloc_pixmap_bo(scrn, scrn->virtualX, 245639413783Smrg scrn->virtualY, scrn->depth, 245739413783Smrg usage, scrn->bitsPerPixel, 245839413783Smrg &pitch, 245939413783Smrg &info->front_surface, 246039413783Smrg &tiling_flags); 246139413783Smrg if (!info->front_buffer) 2462de2362d3Smrg goto fail; 2463de2362d3Smrg 246439413783Smrg scrn->displayWidth = pitch / cpp; 246539413783Smrg 246639413783Smrg if (!info->use_glamor) { 2467de2362d3Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN 246839413783Smrg switch (cpp) { 246939413783Smrg case 4: 247039413783Smrg tiling_flags |= RADEON_TILING_SWAP_32BIT; 247139413783Smrg break; 247239413783Smrg case 2: 247339413783Smrg tiling_flags |= RADEON_TILING_SWAP_16BIT; 247439413783Smrg break; 247539413783Smrg } 247639413783Smrg if (info->ChipFamily < CHIP_FAMILY_R600 && 247739413783Smrg info->r600_shadow_fb && tiling_flags) 247839413783Smrg tiling_flags |= RADEON_TILING_SURFACE; 2479de2362d3Smrg#endif 248039413783Smrg if (tiling_flags) 248139413783Smrg radeon_bo_set_tiling(info->front_buffer->bo.radeon, tiling_flags, pitch); 248239413783Smrg } 2483de2362d3Smrg 2484de2362d3Smrg if (!info->r600_shadow_fb) { 248539413783Smrg if (info->surf_man && !info->use_glamor) 248639413783Smrg *radeon_get_pixmap_surface(ppix) = info->front_surface; 2487de2362d3Smrg screen->ModifyPixmapHeader(ppix, 2488de2362d3Smrg width, height, -1, -1, pitch, NULL); 2489de2362d3Smrg } else { 249039413783Smrg if (radeon_bo_map(info->front_buffer->bo.radeon, 1)) 2491de2362d3Smrg goto fail; 249239413783Smrg fb_shadow = calloc(1, pitch * scrn->virtualY); 249339413783Smrg if (!fb_shadow) 2494de2362d3Smrg goto fail; 2495de2362d3Smrg free(info->fb_shadow); 2496de2362d3Smrg info->fb_shadow = fb_shadow; 2497de2362d3Smrg screen->ModifyPixmapHeader(ppix, 2498de2362d3Smrg width, height, -1, -1, pitch, 2499de2362d3Smrg info->fb_shadow); 2500de2362d3Smrg } 250118781e08Smrg 250218781e08Smrg if (info->use_glamor) 250318781e08Smrg radeon_glamor_create_screen_resources(scrn->pScreen); 250418781e08Smrg 250518781e08Smrg if (!info->r600_shadow_fb) { 250639413783Smrg if (!radeon_set_pixmap_bo(ppix, info->front_buffer)) 250718781e08Smrg goto fail; 250818781e08Smrg } 250918781e08Smrg 25108bf5c682Smrg radeon_pixmap_clear(ppix); 251139413783Smrg radeon_finish(scrn, info->front_buffer); 25120d16fef4Smrg 2513de2362d3Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 2514de2362d3Smrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 2515de2362d3Smrg 2516de2362d3Smrg if (!crtc->enabled) 2517de2362d3Smrg continue; 2518de2362d3Smrg 2519de2362d3Smrg drmmode_set_mode_major(crtc, &crtc->mode, 2520de2362d3Smrg crtc->rotation, crtc->x, crtc->y); 2521de2362d3Smrg } 2522de2362d3Smrg 252339413783Smrg radeon_buffer_unref(&old_front); 2524de2362d3Smrg 252539413783Smrg radeon_kms_update_vram_limit(scrn, pitch * scrn->virtualY); 2526de2362d3Smrg return TRUE; 2527de2362d3Smrg 2528de2362d3Smrg fail: 252939413783Smrg radeon_buffer_unref(&info->front_buffer); 253039413783Smrg info->front_buffer = old_front; 2531de2362d3Smrg scrn->virtualX = old_width; 2532de2362d3Smrg scrn->virtualY = old_height; 2533de2362d3Smrg scrn->displayWidth = old_pitch; 2534de2362d3Smrg 2535de2362d3Smrg return FALSE; 2536de2362d3Smrg} 2537de2362d3Smrg 253839413783Smrgstatic void 253939413783Smrgdrmmode_validate_leases(ScrnInfoPtr scrn) 254039413783Smrg{ 254139413783Smrg#ifdef XF86_LEASE_VERSION 254239413783Smrg ScreenPtr screen = scrn->pScreen; 254339413783Smrg rrScrPrivPtr scr_priv = rrGetScrPriv(screen); 254439413783Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 254539413783Smrg drmModeLesseeListPtr lessees; 254639413783Smrg RRLeasePtr lease, next; 254739413783Smrg int l; 254839413783Smrg 254939413783Smrg /* We can't talk to the kernel about leases when VT switched */ 255039413783Smrg if (!scrn->vtSema) 255139413783Smrg return; 255239413783Smrg 255339413783Smrg lessees = drmModeListLessees(pRADEONEnt->fd); 255439413783Smrg if (!lessees) 255539413783Smrg return; 255639413783Smrg 255739413783Smrg xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) { 255839413783Smrg drmmode_lease_private_ptr lease_private = lease->devPrivate; 255939413783Smrg 256039413783Smrg for (l = 0; l < lessees->count; l++) { 256139413783Smrg if (lessees->lessees[l] == lease_private->lessee_id) 256239413783Smrg break; 256339413783Smrg } 256439413783Smrg 256539413783Smrg /* check to see if the lease has gone away */ 256639413783Smrg if (l == lessees->count) { 256739413783Smrg free(lease_private); 256839413783Smrg lease->devPrivate = NULL; 256939413783Smrg xf86CrtcLeaseTerminated(lease); 257039413783Smrg } 257139413783Smrg } 257239413783Smrg 257339413783Smrg free(lessees); 257439413783Smrg#endif 257539413783Smrg} 257639413783Smrg 257739413783Smrg#ifdef XF86_LEASE_VERSION 257839413783Smrg 257939413783Smrgstatic int 258039413783Smrgdrmmode_create_lease(RRLeasePtr lease, int *fd) 258139413783Smrg{ 258239413783Smrg ScreenPtr screen = lease->screen; 258339413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 258439413783Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 258539413783Smrg drmmode_lease_private_ptr lease_private; 258639413783Smrg int noutput = lease->numOutputs; 258739413783Smrg int ncrtc = lease->numCrtcs; 258839413783Smrg uint32_t *objects; 258939413783Smrg size_t nobjects; 259039413783Smrg int lease_fd; 259139413783Smrg int c, o; 259239413783Smrg int i; 259339413783Smrg 259439413783Smrg nobjects = ncrtc + noutput; 259539413783Smrg if (nobjects == 0 || nobjects > (SIZE_MAX / 4) || 259639413783Smrg ncrtc > (SIZE_MAX - noutput)) 259739413783Smrg return BadValue; 259839413783Smrg 259939413783Smrg lease_private = calloc(1, sizeof (drmmode_lease_private_rec)); 260039413783Smrg if (!lease_private) 260139413783Smrg return BadAlloc; 260239413783Smrg 260339413783Smrg objects = malloc(nobjects * 4); 260439413783Smrg if (!objects) { 260539413783Smrg free(lease_private); 260639413783Smrg return BadAlloc; 260739413783Smrg } 260839413783Smrg 260939413783Smrg i = 0; 261039413783Smrg 261139413783Smrg /* Add CRTC ids */ 261239413783Smrg for (c = 0; c < ncrtc; c++) { 261339413783Smrg xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate; 261439413783Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 261539413783Smrg 261639413783Smrg objects[i++] = drmmode_crtc->mode_crtc->crtc_id; 261739413783Smrg } 261839413783Smrg 261939413783Smrg /* Add connector ids */ 262039413783Smrg for (o = 0; o < noutput; o++) { 262139413783Smrg xf86OutputPtr output = lease->outputs[o]->devPrivate; 262239413783Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 262339413783Smrg 262439413783Smrg objects[i++] = drmmode_output->mode_output->connector_id; 262539413783Smrg } 262639413783Smrg 262739413783Smrg /* call kernel to create lease */ 262839413783Smrg assert (i == nobjects); 262939413783Smrg 263039413783Smrg lease_fd = drmModeCreateLease(pRADEONEnt->fd, objects, nobjects, 0, 263139413783Smrg &lease_private->lessee_id); 263239413783Smrg 263339413783Smrg free(objects); 263439413783Smrg 263539413783Smrg if (lease_fd < 0) { 263639413783Smrg free(lease_private); 263739413783Smrg return BadMatch; 263839413783Smrg } 263939413783Smrg 264039413783Smrg lease->devPrivate = lease_private; 264139413783Smrg 264239413783Smrg xf86CrtcLeaseStarted(lease); 264339413783Smrg 264439413783Smrg *fd = lease_fd; 264539413783Smrg return Success; 264639413783Smrg} 264739413783Smrg 264839413783Smrgstatic void 264939413783Smrgdrmmode_terminate_lease(RRLeasePtr lease) 265039413783Smrg{ 265139413783Smrg drmmode_lease_private_ptr lease_private = lease->devPrivate; 265239413783Smrg ScreenPtr screen = lease->screen; 265339413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 265439413783Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 265539413783Smrg 265639413783Smrg if (drmModeRevokeLease(pRADEONEnt->fd, lease_private->lessee_id) == 0) { 265739413783Smrg free(lease_private); 265839413783Smrg lease->devPrivate = NULL; 265939413783Smrg xf86CrtcLeaseTerminated(lease); 266039413783Smrg } 266139413783Smrg} 266239413783Smrg 266339413783Smrg#endif // XF86_LEASE_VERSION 266439413783Smrg 2665de2362d3Smrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { 266639413783Smrg .resize = drmmode_xf86crtc_resize, 266739413783Smrg#ifdef XF86_LEASE_VERSION 266839413783Smrg .create_lease = drmmode_create_lease, 266939413783Smrg .terminate_lease = drmmode_terminate_lease 267039413783Smrg#endif 2671de2362d3Smrg}; 2672de2362d3Smrg 2673de2362d3Smrgstatic void 267418781e08Smrgdrmmode_flip_abort(xf86CrtcPtr crtc, void *event_data) 2675de2362d3Smrg{ 26768bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 26778bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 267818781e08Smrg drmmode_flipdata_ptr flipdata = event_data; 267939413783Smrg int crtc_id = drmmode_get_crtc_id(crtc); 268039413783Smrg struct drmmode_fb **fb = &flipdata->fb[crtc_id]; 268139413783Smrg 268239413783Smrg if (drmmode_crtc->flip_pending == *fb) { 268339413783Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->flip_pending, 268439413783Smrg NULL); 268539413783Smrg } 268639413783Smrg drmmode_fb_reference(pRADEONEnt->fd, fb, NULL); 268718781e08Smrg 268818781e08Smrg if (--flipdata->flip_count == 0) { 268918781e08Smrg if (!flipdata->fe_crtc) 269018781e08Smrg flipdata->fe_crtc = crtc; 269118781e08Smrg flipdata->abort(flipdata->fe_crtc, flipdata->event_data); 269218781e08Smrg free(flipdata); 269318781e08Smrg } 2694de2362d3Smrg} 2695de2362d3Smrg 2696de2362d3Smrgstatic void 269718781e08Smrgdrmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data) 2698de2362d3Smrg{ 26998bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 27008bf5c682Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 270118781e08Smrg drmmode_flipdata_ptr flipdata = event_data; 270239413783Smrg int crtc_id = drmmode_get_crtc_id(crtc); 270339413783Smrg struct drmmode_fb **fb = &flipdata->fb[crtc_id]; 2704de2362d3Smrg 2705de2362d3Smrg /* Is this the event whose info shall be delivered to higher level? */ 270618781e08Smrg if (crtc == flipdata->fe_crtc) { 2707de2362d3Smrg /* Yes: Cache msc, ust for later delivery. */ 2708de2362d3Smrg flipdata->fe_frame = frame; 270918781e08Smrg flipdata->fe_usec = usec; 2710de2362d3Smrg } 2711de2362d3Smrg 2712446f62d6Smrg if (*fb) { 2713446f62d6Smrg if (drmmode_crtc->flip_pending == *fb) { 2714446f62d6Smrg drmmode_fb_reference(pRADEONEnt->fd, 2715446f62d6Smrg &drmmode_crtc->flip_pending, NULL); 2716446f62d6Smrg } 2717446f62d6Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, *fb); 2718446f62d6Smrg drmmode_fb_reference(pRADEONEnt->fd, fb, NULL); 27198bf5c682Smrg } 27208bf5c682Smrg 272118781e08Smrg if (--flipdata->flip_count == 0) { 272218781e08Smrg /* Deliver MSC & UST from reference/current CRTC to flip event 272318781e08Smrg * handler 272418781e08Smrg */ 272518781e08Smrg if (flipdata->fe_crtc) 272618781e08Smrg flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame, 272718781e08Smrg flipdata->fe_usec, flipdata->event_data); 272818781e08Smrg else 272918781e08Smrg flipdata->handler(crtc, frame, usec, flipdata->event_data); 2730de2362d3Smrg 273118781e08Smrg free(flipdata); 273218781e08Smrg } 2733de2362d3Smrg} 2734de2362d3Smrg 2735de2362d3Smrg 273618781e08Smrg#if HAVE_NOTIFY_FD 273718781e08Smrgstatic void 273818781e08Smrgdrm_notify_fd(int fd, int ready, void *data) 273918781e08Smrg#else 2740de2362d3Smrgstatic void 2741de2362d3Smrgdrm_wakeup_handler(pointer data, int err, pointer p) 274218781e08Smrg#endif 2743de2362d3Smrg{ 274439413783Smrg drmmode_ptr drmmode = data; 274539413783Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(drmmode->scrn); 27468bf5c682Smrg 274718781e08Smrg#if !HAVE_NOTIFY_FD 2748de2362d3Smrg fd_set *read_mask = p; 2749de2362d3Smrg 27508bf5c682Smrg if (err >= 0 && FD_ISSET(pRADEONEnt->fd, read_mask)) 275118781e08Smrg#endif 275218781e08Smrg { 275339413783Smrg radeon_drm_handle_event(pRADEONEnt->fd, &drmmode->event_context); 2754de2362d3Smrg } 2755de2362d3Smrg} 2756de2362d3Smrg 27578bf5c682Smrgstatic Bool drmmode_probe_page_flip_target(RADEONEntPtr pRADEONEnt) 27583ed65abbSmrg{ 27593ed65abbSmrg#ifdef DRM_CAP_PAGE_FLIP_TARGET 27603ed65abbSmrg uint64_t cap_value; 27613ed65abbSmrg 27628bf5c682Smrg return drmGetCap(pRADEONEnt->fd, DRM_CAP_PAGE_FLIP_TARGET, 27633ed65abbSmrg &cap_value) == 0 && cap_value != 0; 27643ed65abbSmrg#else 27653ed65abbSmrg return FALSE; 27663ed65abbSmrg#endif 27673ed65abbSmrg} 27683ed65abbSmrg 27693ed65abbSmrgstatic int 27708bf5c682Smrgdrmmode_page_flip(RADEONEntPtr pRADEONEnt, 27718bf5c682Smrg drmmode_crtc_private_ptr drmmode_crtc, int fb_id, 27723ed65abbSmrg uint32_t flags, uintptr_t drm_queue_seq) 27733ed65abbSmrg{ 27743ed65abbSmrg flags |= DRM_MODE_PAGE_FLIP_EVENT; 27758bf5c682Smrg return drmModePageFlip(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 27763ed65abbSmrg fb_id, flags, (void*)drm_queue_seq); 27773ed65abbSmrg} 27783ed65abbSmrg 27793ed65abbSmrgint 27803ed65abbSmrgdrmmode_page_flip_target_absolute(RADEONEntPtr pRADEONEnt, 27813ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc, 27823ed65abbSmrg int fb_id, uint32_t flags, 27833ed65abbSmrg uintptr_t drm_queue_seq, uint32_t target_msc) 27843ed65abbSmrg{ 27853ed65abbSmrg#ifdef DRM_MODE_PAGE_FLIP_TARGET 27863ed65abbSmrg if (pRADEONEnt->has_page_flip_target) { 27873ed65abbSmrg flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE; 27888bf5c682Smrg return drmModePageFlipTarget(pRADEONEnt->fd, 27893ed65abbSmrg drmmode_crtc->mode_crtc->crtc_id, 27903ed65abbSmrg fb_id, flags, (void*)drm_queue_seq, 27913ed65abbSmrg target_msc); 27923ed65abbSmrg } 27933ed65abbSmrg#endif 27943ed65abbSmrg 27958bf5c682Smrg return drmmode_page_flip(pRADEONEnt, drmmode_crtc, fb_id, flags, 27968bf5c682Smrg drm_queue_seq); 27973ed65abbSmrg} 27983ed65abbSmrg 27993ed65abbSmrgint 28003ed65abbSmrgdrmmode_page_flip_target_relative(RADEONEntPtr pRADEONEnt, 28013ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc, 28023ed65abbSmrg int fb_id, uint32_t flags, 28033ed65abbSmrg uintptr_t drm_queue_seq, uint32_t target_msc) 28043ed65abbSmrg{ 28053ed65abbSmrg#ifdef DRM_MODE_PAGE_FLIP_TARGET 28063ed65abbSmrg if (pRADEONEnt->has_page_flip_target) { 28073ed65abbSmrg flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE; 28088bf5c682Smrg return drmModePageFlipTarget(pRADEONEnt->fd, 28093ed65abbSmrg drmmode_crtc->mode_crtc->crtc_id, 28103ed65abbSmrg fb_id, flags, (void*)drm_queue_seq, 28113ed65abbSmrg target_msc); 28123ed65abbSmrg } 28133ed65abbSmrg#endif 28143ed65abbSmrg 28158bf5c682Smrg return drmmode_page_flip(pRADEONEnt, drmmode_crtc, fb_id, flags, 28168bf5c682Smrg drm_queue_seq); 28173ed65abbSmrg} 28183ed65abbSmrg 2819de2362d3SmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) 2820de2362d3Smrg{ 282118781e08Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 282218781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 2823de2362d3Smrg int i, num_dvi = 0, num_hdmi = 0; 282418781e08Smrg drmModeResPtr mode_res; 282518781e08Smrg unsigned int crtcs_needed = 0; 2826446f62d6Smrg unsigned int crtcs_got = 0; 282718781e08Smrg char *bus_id_string, *provider_name; 2828de2362d3Smrg 2829de2362d3Smrg xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); 2830de2362d3Smrg 2831de2362d3Smrg drmmode->scrn = pScrn; 28328bf5c682Smrg mode_res = drmModeGetResources(pRADEONEnt->fd); 283318781e08Smrg if (!mode_res) 2834de2362d3Smrg return FALSE; 2835de2362d3Smrg 283618781e08Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 283718781e08Smrg "Initializing outputs ...\n"); 283818781e08Smrg for (i = 0; i < mode_res->count_connectors; i++) 283918781e08Smrg crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, 284018781e08Smrg i, &num_dvi, &num_hdmi, 0); 284118781e08Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 284218781e08Smrg "%d crtcs needed for screen.\n", crtcs_needed); 284318781e08Smrg 28448bf5c682Smrg /* Need per-screen drmmode_crtc_funcs, based on our global template, 28458bf5c682Smrg * so we can disable some functions, depending on screen settings. 28468bf5c682Smrg */ 28478bf5c682Smrg info->drmmode_crtc_funcs = drmmode_crtc_funcs; 28488bf5c682Smrg 284918781e08Smrg if (info->r600_shadow_fb) { 285018781e08Smrg /* Rotation requires hardware acceleration */ 28518bf5c682Smrg info->drmmode_crtc_funcs.shadow_allocate = NULL; 28528bf5c682Smrg info->drmmode_crtc_funcs.shadow_create = NULL; 28538bf5c682Smrg info->drmmode_crtc_funcs.shadow_destroy = NULL; 285418781e08Smrg } 285518781e08Smrg 28568bf5c682Smrg /* Hw gamma lut's are currently bypassed by the hw at color depth 30, 28578bf5c682Smrg * so spare the server the effort to compute and update the cluts. 28588bf5c682Smrg */ 28598bf5c682Smrg if (pScrn->depth == 30) 28608bf5c682Smrg info->drmmode_crtc_funcs.gamma_set = NULL; 28618bf5c682Smrg 286218781e08Smrg drmmode->count_crtcs = mode_res->count_crtcs; 286318781e08Smrg xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, mode_res->max_height); 286418781e08Smrg 2865446f62d6Smrg for (i = 0; i < mode_res->count_crtcs; i++) { 286618781e08Smrg if (!xf86IsEntityShared(pScrn->entityList[0]) || 2867446f62d6Smrg (crtcs_got < crtcs_needed && 2868446f62d6Smrg !(pRADEONEnt->assigned_crtcs & (1 << i)))) 2869446f62d6Smrg crtcs_got += drmmode_crtc_init(pScrn, drmmode, mode_res, i); 2870446f62d6Smrg } 2871de2362d3Smrg 287218781e08Smrg /* All ZaphodHeads outputs provided with matching crtcs? */ 2873446f62d6Smrg if (crtcs_got < crtcs_needed) { 2874446f62d6Smrg if (crtcs_got == 0) { 2875446f62d6Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 2876446f62d6Smrg "No ZaphodHeads CRTC available, needed %u\n", 2877446f62d6Smrg crtcs_needed); 2878446f62d6Smrg return FALSE; 2879446f62d6Smrg } 2880446f62d6Smrg 288118781e08Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 288218781e08Smrg "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n", 288318781e08Smrg crtcs_needed); 2884446f62d6Smrg } 2885de2362d3Smrg 2886de2362d3Smrg /* workout clones */ 288718781e08Smrg drmmode_clones_init(pScrn, drmmode, mode_res); 288818781e08Smrg 288918781e08Smrg bus_id_string = DRICreatePCIBusID(info->PciInfo); 289018781e08Smrg XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, bus_id_string); 289118781e08Smrg free(bus_id_string); 289218781e08Smrg xf86ProviderSetup(pScrn, NULL, provider_name); 289318781e08Smrg free(provider_name); 2894de2362d3Smrg 2895de2362d3Smrg xf86InitialConfiguration(pScrn, TRUE); 2896de2362d3Smrg 28978bf5c682Smrg pRADEONEnt->has_page_flip_target = drmmode_probe_page_flip_target(pRADEONEnt); 28983ed65abbSmrg 289918781e08Smrg drmModeFreeResources(mode_res); 2900de2362d3Smrg return TRUE; 2901de2362d3Smrg} 2902de2362d3Smrg 2903de2362d3Smrgvoid drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 2904de2362d3Smrg{ 2905de2362d3Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 2906de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 2907de2362d3Smrg 290818781e08Smrg if (info->dri2.pKernelDRMVersion->version_minor < 4) 290918781e08Smrg return; 291018781e08Smrg 291118781e08Smrg info->drmmode_inited = TRUE; 291218781e08Smrg if (pRADEONEnt->fd_wakeup_registered != serverGeneration) { 291318781e08Smrg#if HAVE_NOTIFY_FD 291439413783Smrg SetNotifyFd(pRADEONEnt->fd, drm_notify_fd, X_NOTIFY_READ, 291539413783Smrg &info->drmmode); 291618781e08Smrg#else 29178bf5c682Smrg AddGeneralSocket(pRADEONEnt->fd); 2918de2362d3Smrg RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, 291939413783Smrg drm_wakeup_handler, 292039413783Smrg &info->drmmode); 292118781e08Smrg#endif 2922de2362d3Smrg pRADEONEnt->fd_wakeup_registered = serverGeneration; 292318781e08Smrg pRADEONEnt->fd_wakeup_ref = 1; 292418781e08Smrg } else 292518781e08Smrg pRADEONEnt->fd_wakeup_ref++; 292618781e08Smrg} 292718781e08Smrg 292818781e08Smrgvoid drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 292918781e08Smrg{ 293018781e08Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 293118781e08Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 293218781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 293318781e08Smrg int c; 293418781e08Smrg 293518781e08Smrg if (info->dri2.pKernelDRMVersion->version_minor < 4 || !info->drmmode_inited) 293618781e08Smrg return; 293718781e08Smrg 2938446f62d6Smrg for (c = 0; c < config->num_crtc; c++) 2939446f62d6Smrg drmmode_crtc_scanout_free(config->crtc[c]); 2940446f62d6Smrg 294118781e08Smrg if (pRADEONEnt->fd_wakeup_registered == serverGeneration && 294218781e08Smrg !--pRADEONEnt->fd_wakeup_ref) { 294318781e08Smrg#if HAVE_NOTIFY_FD 29448bf5c682Smrg RemoveNotifyFd(pRADEONEnt->fd); 294518781e08Smrg#else 29468bf5c682Smrg RemoveGeneralSocket(pRADEONEnt->fd); 294718781e08Smrg RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, 29488bf5c682Smrg drm_wakeup_handler, pScrn); 294918781e08Smrg#endif 295018781e08Smrg } 2951de2362d3Smrg} 2952de2362d3Smrg 295318781e08Smrg 2954de2362d3SmrgBool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, struct radeon_bo_manager *bufmgr) 2955de2362d3Smrg{ 2956de2362d3Smrg drmmode->bufmgr = bufmgr; 2957de2362d3Smrg return TRUE; 2958de2362d3Smrg} 2959de2362d3Smrg 2960de2362d3Smrg 29618bf5c682Smrgstatic void drmmode_sprite_do_set_cursor(struct radeon_device_priv *device_priv, 29628bf5c682Smrg ScrnInfoPtr scrn, int x, int y) 29638bf5c682Smrg{ 29648bf5c682Smrg RADEONInfoPtr info = RADEONPTR(scrn); 29658bf5c682Smrg CursorPtr cursor = device_priv->cursor; 29668bf5c682Smrg Bool sprite_visible = device_priv->sprite_visible; 29678bf5c682Smrg 29688bf5c682Smrg if (cursor) { 29698bf5c682Smrg x -= cursor->bits->xhot; 29708bf5c682Smrg y -= cursor->bits->yhot; 29718bf5c682Smrg 29728bf5c682Smrg device_priv->sprite_visible = 29738bf5c682Smrg x < scrn->virtualX && y < scrn->virtualY && 29748bf5c682Smrg (x + cursor->bits->width > 0) && 29758bf5c682Smrg (y + cursor->bits->height > 0); 29768bf5c682Smrg } else { 29778bf5c682Smrg device_priv->sprite_visible = FALSE; 29788bf5c682Smrg } 29798bf5c682Smrg 29808bf5c682Smrg info->sprites_visible += device_priv->sprite_visible - sprite_visible; 29818bf5c682Smrg} 29828bf5c682Smrg 298339413783Smrgstatic void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 298439413783Smrg CursorPtr pCursor, int x, int y) 29858bf5c682Smrg{ 29868bf5c682Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 29878bf5c682Smrg RADEONInfoPtr info = RADEONPTR(scrn); 29888bf5c682Smrg struct radeon_device_priv *device_priv = 29898bf5c682Smrg dixLookupScreenPrivate(&pDev->devPrivates, 29908bf5c682Smrg &radeon_device_private_key, pScreen); 29918bf5c682Smrg 29928bf5c682Smrg device_priv->cursor = pCursor; 29938bf5c682Smrg drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 29948bf5c682Smrg 299539413783Smrg info->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y); 29968bf5c682Smrg} 29978bf5c682Smrg 299839413783Smrgstatic void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 299939413783Smrg int x, int y) 30008bf5c682Smrg{ 30018bf5c682Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 30028bf5c682Smrg RADEONInfoPtr info = RADEONPTR(scrn); 30038bf5c682Smrg struct radeon_device_priv *device_priv = 30048bf5c682Smrg dixLookupScreenPrivate(&pDev->devPrivates, 30058bf5c682Smrg &radeon_device_private_key, pScreen); 30068bf5c682Smrg 30078bf5c682Smrg drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 30088bf5c682Smrg 300939413783Smrg info->SpriteFuncs->MoveCursor(pDev, pScreen, x, y); 301039413783Smrg} 301139413783Smrg 301239413783Smrgstatic Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev, 301339413783Smrg ScreenPtr pScreen, 301439413783Smrg CursorPtr pCursor) 301539413783Smrg{ 301639413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 301739413783Smrg RADEONInfoPtr info = RADEONPTR(scrn); 301839413783Smrg 301939413783Smrg return info->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor); 302039413783Smrg} 302139413783Smrg 302239413783Smrgstatic Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev, 302339413783Smrg ScreenPtr pScreen, 302439413783Smrg CursorPtr pCursor) 302539413783Smrg{ 302639413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 302739413783Smrg RADEONInfoPtr info = RADEONPTR(scrn); 302839413783Smrg 302939413783Smrg return info->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor); 303039413783Smrg} 303139413783Smrg 303239413783Smrgstatic Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev, 303339413783Smrg ScreenPtr pScreen) 303439413783Smrg{ 303539413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 303639413783Smrg RADEONInfoPtr info = RADEONPTR(scrn); 303739413783Smrg 303839413783Smrg return info->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen); 30398bf5c682Smrg} 3040de2362d3Smrg 304139413783Smrgstatic void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev, 304239413783Smrg ScreenPtr pScreen) 304339413783Smrg{ 304439413783Smrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 304539413783Smrg RADEONInfoPtr info = RADEONPTR(scrn); 304639413783Smrg 304739413783Smrg info->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen); 304839413783Smrg} 304939413783Smrg 305039413783SmrgmiPointerSpriteFuncRec drmmode_sprite_funcs = { 305139413783Smrg .RealizeCursor = drmmode_sprite_realize_realize_cursor, 305239413783Smrg .UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor, 305339413783Smrg .SetCursor = drmmode_sprite_set_cursor, 305439413783Smrg .MoveCursor = drmmode_sprite_move_cursor, 305539413783Smrg .DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize, 305639413783Smrg .DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup, 305739413783Smrg}; 305839413783Smrg 305939413783Smrg 3060de2362d3Smrgvoid drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y) 3061de2362d3Smrg{ 3062de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 3063de2362d3Smrg xf86OutputPtr output = config->output[config->compat_output]; 3064de2362d3Smrg xf86CrtcPtr crtc = output->crtc; 3065de2362d3Smrg 3066de2362d3Smrg if (crtc && crtc->enabled) { 3067de2362d3Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 3068de2362d3Smrg x, y); 3069de2362d3Smrg } 3070de2362d3Smrg} 3071de2362d3Smrg 307218781e08SmrgBool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, 307318781e08Smrg Bool set_hw) 3074de2362d3Smrg{ 3075de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 30768bf5c682Smrg unsigned num_desired = 0, num_on = 0; 3077de2362d3Smrg int c; 3078de2362d3Smrg 30798bf5c682Smrg /* First, disable all unused CRTCs */ 30808bf5c682Smrg if (set_hw) { 30818bf5c682Smrg for (c = 0; c < config->num_crtc; c++) { 30828bf5c682Smrg xf86CrtcPtr crtc = config->crtc[c]; 30838bf5c682Smrg 30848bf5c682Smrg /* Skip disabled CRTCs */ 30858bf5c682Smrg if (crtc->enabled) 30868bf5c682Smrg continue; 30878bf5c682Smrg 308839413783Smrg drmmode_crtc_dpms(crtc, DPMSModeOff); 30898bf5c682Smrg } 30908bf5c682Smrg } 30918bf5c682Smrg 30928bf5c682Smrg /* Then, try setting the chosen mode on each CRTC */ 3093de2362d3Smrg for (c = 0; c < config->num_crtc; c++) { 3094de2362d3Smrg xf86CrtcPtr crtc = config->crtc[c]; 3095de2362d3Smrg xf86OutputPtr output = NULL; 3096de2362d3Smrg int o; 3097de2362d3Smrg 30988bf5c682Smrg if (!crtc->enabled) 3099de2362d3Smrg continue; 3100de2362d3Smrg 3101de2362d3Smrg if (config->output[config->compat_output]->crtc == crtc) 3102de2362d3Smrg output = config->output[config->compat_output]; 3103de2362d3Smrg else 3104de2362d3Smrg { 3105de2362d3Smrg for (o = 0; o < config->num_output; o++) 3106de2362d3Smrg if (config->output[o]->crtc == crtc) 3107de2362d3Smrg { 3108de2362d3Smrg output = config->output[o]; 3109de2362d3Smrg break; 3110de2362d3Smrg } 3111de2362d3Smrg } 3112de2362d3Smrg /* paranoia */ 3113de2362d3Smrg if (!output) 3114de2362d3Smrg continue; 3115de2362d3Smrg 31168bf5c682Smrg num_desired++; 31178bf5c682Smrg 3118de2362d3Smrg /* Mark that we'll need to re-set the mode for sure */ 3119de2362d3Smrg memset(&crtc->mode, 0, sizeof(crtc->mode)); 3120de2362d3Smrg if (!crtc->desiredMode.CrtcHDisplay) 3121de2362d3Smrg { 3122de2362d3Smrg DisplayModePtr mode = xf86OutputFindClosestMode (output, pScrn->currentMode); 3123de2362d3Smrg 31248bf5c682Smrg if (!mode) { 31258bf5c682Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 31268bf5c682Smrg "Failed to find mode for CRTC %d\n", c); 31278bf5c682Smrg continue; 31288bf5c682Smrg } 3129de2362d3Smrg crtc->desiredMode = *mode; 3130de2362d3Smrg crtc->desiredRotation = RR_Rotate_0; 3131de2362d3Smrg crtc->desiredX = 0; 3132de2362d3Smrg crtc->desiredY = 0; 3133de2362d3Smrg } 3134de2362d3Smrg 313518781e08Smrg if (set_hw) { 31368bf5c682Smrg if (crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, 31378bf5c682Smrg crtc->desiredRotation, 31388bf5c682Smrg crtc->desiredX, 31398bf5c682Smrg crtc->desiredY)) { 31408bf5c682Smrg num_on++; 31418bf5c682Smrg } else { 31428bf5c682Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 31438bf5c682Smrg "Failed to set mode on CRTC %d\n", c); 314439413783Smrg RRCrtcSet(crtc->randr_crtc, NULL, crtc->x, crtc->y, 314539413783Smrg crtc->rotation, 0, NULL); 31468bf5c682Smrg } 314718781e08Smrg } else { 314818781e08Smrg crtc->mode = crtc->desiredMode; 314918781e08Smrg crtc->rotation = crtc->desiredRotation; 315018781e08Smrg crtc->x = crtc->desiredX; 315118781e08Smrg crtc->y = crtc->desiredY; 31528bf5c682Smrg if (drmmode_handle_transform(crtc)) 31538bf5c682Smrg num_on++; 315418781e08Smrg } 3155de2362d3Smrg } 31568bf5c682Smrg 31578bf5c682Smrg if (num_on == 0 && num_desired > 0) { 31588bf5c682Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to enable any CRTC\n"); 31598bf5c682Smrg return FALSE; 31608bf5c682Smrg } 31618bf5c682Smrg 316239413783Smrg /* Validate leases on VT re-entry */ 3163446f62d6Smrg if (dixPrivateKeyRegistered(rrPrivKey)) 3164446f62d6Smrg drmmode_validate_leases(pScrn); 316539413783Smrg 3166de2362d3Smrg return TRUE; 3167de2362d3Smrg} 3168de2362d3Smrg 316918781e08SmrgBool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn) 3170de2362d3Smrg{ 3171de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 317239413783Smrg int i; 3173de2362d3Smrg 317418781e08Smrg if (xf86_config->num_crtc) { 317518781e08Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 317618781e08Smrg "Initializing kms color map\n"); 317718781e08Smrg if (!miCreateDefColormap(pScreen)) 317818781e08Smrg return FALSE; 31798bf5c682Smrg 31808bf5c682Smrg /* All radeons support 10 bit CLUTs. They get bypassed at depth 30. */ 318139413783Smrg if (pScrn->depth != 30) { 318239413783Smrg if (!xf86HandleColormaps(pScreen, 256, 10, NULL, NULL, 318339413783Smrg CMAP_PALETTED_TRUECOLOR 318439413783Smrg | CMAP_RELOAD_ON_MODE_SWITCH)) 318539413783Smrg return FALSE; 318639413783Smrg 318739413783Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 318839413783Smrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 318939413783Smrg 319039413783Smrg drmmode_crtc_gamma_do_set(crtc, crtc->gamma_red, 319139413783Smrg crtc->gamma_green, 319239413783Smrg crtc->gamma_blue, 319339413783Smrg crtc->gamma_size); 319439413783Smrg } 319539413783Smrg } 319618781e08Smrg } 319739413783Smrg 319818781e08Smrg return TRUE; 319918781e08Smrg} 32007314432eSmrg 320118781e08Smrgstatic Bool 320218781e08Smrgdrmmode_find_output(ScrnInfoPtr scrn, int output_id, int *num_dvi, 320318781e08Smrg int *num_hdmi) 320418781e08Smrg{ 320518781e08Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 320618781e08Smrg int i; 32077314432eSmrg 320818781e08Smrg for (i = 0; i < config->num_output; i++) { 320918781e08Smrg xf86OutputPtr output = config->output[i]; 321018781e08Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 321118781e08Smrg 321218781e08Smrg if (drmmode_output->output_id == output_id) { 321318781e08Smrg switch(drmmode_output->mode_output->connector_type) { 321418781e08Smrg case DRM_MODE_CONNECTOR_DVII: 321518781e08Smrg case DRM_MODE_CONNECTOR_DVID: 321618781e08Smrg case DRM_MODE_CONNECTOR_DVIA: 321718781e08Smrg (*num_dvi)++; 321818781e08Smrg break; 321918781e08Smrg case DRM_MODE_CONNECTOR_HDMIA: 322018781e08Smrg case DRM_MODE_CONNECTOR_HDMIB: 322118781e08Smrg (*num_hdmi)++; 322218781e08Smrg break; 322318781e08Smrg } 322418781e08Smrg 322518781e08Smrg return TRUE; 322618781e08Smrg } 322718781e08Smrg } 322818781e08Smrg 322918781e08Smrg return FALSE; 32307314432eSmrg} 32317314432eSmrg 323218781e08Smrgvoid 323318781e08Smrgradeon_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode) 32340d16fef4Smrg{ 323518781e08Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 323618781e08Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 323718781e08Smrg drmModeResPtr mode_res; 323818781e08Smrg int i, j; 323918781e08Smrg Bool found; 324018781e08Smrg Bool changed = FALSE; 324118781e08Smrg int num_dvi = 0, num_hdmi = 0; 324218781e08Smrg 32438bf5c682Smrg /* Try to re-set the mode on all the connectors with a BAD link-state: 32448bf5c682Smrg * This may happen if a link degrades and a new modeset is necessary, using 32458bf5c682Smrg * different link-training parameters. If the kernel found that the current 32468bf5c682Smrg * mode is not achievable anymore, it should have pruned the mode before 32478bf5c682Smrg * sending the hotplug event. Try to re-set the currently-set mode to keep 32488bf5c682Smrg * the display alive, this will fail if the mode has been pruned. 32498bf5c682Smrg * In any case, we will send randr events for the Desktop Environment to 32508bf5c682Smrg * deal with it, if it wants to. 32518bf5c682Smrg */ 32528bf5c682Smrg for (i = 0; i < config->num_output; i++) { 32538bf5c682Smrg xf86OutputPtr output = config->output[i]; 32548bf5c682Smrg xf86CrtcPtr crtc = output->crtc; 32558bf5c682Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 32568bf5c682Smrg 32578bf5c682Smrg drmmode_output_detect(output); 32588bf5c682Smrg 32598bf5c682Smrg if (!crtc || !drmmode_output->mode_output) 32608bf5c682Smrg continue; 32618bf5c682Smrg 32628bf5c682Smrg /* Get an updated view of the properties for the current connector and 32638bf5c682Smrg * look for the link-status property 32648bf5c682Smrg */ 32658bf5c682Smrg for (j = 0; j < drmmode_output->num_props; j++) { 32668bf5c682Smrg drmmode_prop_ptr p = &drmmode_output->props[j]; 32678bf5c682Smrg 32688bf5c682Smrg if (!strcmp(p->mode_prop->name, "link-status")) { 32698bf5c682Smrg if (p->value != DRM_MODE_LINK_STATUS_BAD) 32708bf5c682Smrg break; 32718bf5c682Smrg 32728bf5c682Smrg /* the connector got a link failure, re-set the current mode */ 32738bf5c682Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 32748bf5c682Smrg crtc->x, crtc->y); 32758bf5c682Smrg 32768bf5c682Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 32778bf5c682Smrg "hotplug event: connector %u's link-state is BAD, " 32788bf5c682Smrg "tried resetting the current mode. You may be left" 32798bf5c682Smrg "with a black screen if this fails...\n", 32808bf5c682Smrg drmmode_output->mode_output->connector_id); 32818bf5c682Smrg 32828bf5c682Smrg break; 32838bf5c682Smrg } 32848bf5c682Smrg } 32858bf5c682Smrg } 32868bf5c682Smrg 32878bf5c682Smrg mode_res = drmModeGetResources(pRADEONEnt->fd); 328818781e08Smrg if (!mode_res) 328918781e08Smrg goto out; 329018781e08Smrg 329118781e08Smrgrestart_destroy: 329218781e08Smrg for (i = 0; i < config->num_output; i++) { 329318781e08Smrg xf86OutputPtr output = config->output[i]; 329418781e08Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 329518781e08Smrg found = FALSE; 329618781e08Smrg for (j = 0; j < mode_res->count_connectors; j++) { 329718781e08Smrg if (mode_res->connectors[j] == drmmode_output->output_id) { 329818781e08Smrg found = TRUE; 329918781e08Smrg break; 330018781e08Smrg } 330118781e08Smrg } 330218781e08Smrg if (found) 330318781e08Smrg continue; 330418781e08Smrg 330518781e08Smrg drmModeFreeConnector(drmmode_output->mode_output); 330618781e08Smrg drmmode_output->mode_output = NULL; 330718781e08Smrg drmmode_output->output_id = -1; 330818781e08Smrg 330918781e08Smrg changed = TRUE; 331018781e08Smrg if (drmmode->delete_dp_12_displays) { 331118781e08Smrg RROutputDestroy(output->randr_output); 331218781e08Smrg xf86OutputDestroy(output); 331318781e08Smrg goto restart_destroy; 331418781e08Smrg } 331518781e08Smrg } 331618781e08Smrg 331718781e08Smrg /* find new output ids we don't have outputs for */ 331818781e08Smrg for (i = 0; i < mode_res->count_connectors; i++) { 3319446f62d6Smrg for (j = 0; j < pRADEONEnt->num_scrns; j++) { 3320446f62d6Smrg if (drmmode_find_output(pRADEONEnt->scrn[j], 3321446f62d6Smrg mode_res->connectors[i], 3322446f62d6Smrg &num_dvi, &num_hdmi)) 3323446f62d6Smrg break; 3324446f62d6Smrg } 3325446f62d6Smrg 3326446f62d6Smrg if (j < pRADEONEnt->num_scrns) 332718781e08Smrg continue; 332818781e08Smrg 332918781e08Smrg if (drmmode_output_init(scrn, drmmode, mode_res, i, &num_dvi, 333018781e08Smrg &num_hdmi, 1) != 0) 333118781e08Smrg changed = TRUE; 333218781e08Smrg } 333318781e08Smrg 333439413783Smrg /* Check to see if a lessee has disappeared */ 333539413783Smrg drmmode_validate_leases(scrn); 333639413783Smrg 3337446f62d6Smrg if (changed) { 333818781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0) 333918781e08Smrg RRSetChanged(xf86ScrnToScreen(scrn)); 334018781e08Smrg#else 334118781e08Smrg rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen); 334218781e08Smrg rrScrPriv->changed = TRUE; 33430d16fef4Smrg#endif 334418781e08Smrg RRTellChanged(xf86ScrnToScreen(scrn)); 334518781e08Smrg } 33467821949aSmrg 334718781e08Smrg drmModeFreeResources(mode_res); 334818781e08Smrgout: 334918781e08Smrg RRGetInfo(xf86ScrnToScreen(scrn), TRUE); 335018781e08Smrg} 3351de2362d3Smrg#ifdef HAVE_LIBUDEV 3352de2362d3Smrgstatic void 3353de2362d3Smrgdrmmode_handle_uevents(int fd, void *closure) 3354de2362d3Smrg{ 3355de2362d3Smrg drmmode_ptr drmmode = closure; 3356de2362d3Smrg ScrnInfoPtr scrn = drmmode->scrn; 3357de2362d3Smrg struct udev_device *dev; 335818781e08Smrg Bool received = FALSE; 33593ed65abbSmrg struct timeval tv = { 0, 0 }; 33603ed65abbSmrg fd_set readfd; 33613ed65abbSmrg 33623ed65abbSmrg FD_ZERO(&readfd); 33633ed65abbSmrg FD_SET(fd, &readfd); 33643ed65abbSmrg 33653ed65abbSmrg while (select(fd + 1, &readfd, NULL, NULL, &tv) > 0 && 33663ed65abbSmrg FD_ISSET(fd, &readfd)) { 33673ed65abbSmrg /* select() ensured that this will not block */ 33683ed65abbSmrg dev = udev_monitor_receive_device(drmmode->uevent_monitor); 33693ed65abbSmrg if (dev) { 33703ed65abbSmrg udev_device_unref(dev); 33713ed65abbSmrg received = TRUE; 33723ed65abbSmrg } 337318781e08Smrg } 337418781e08Smrg 337518781e08Smrg if (received) 337618781e08Smrg radeon_mode_hotplug(scrn, drmmode); 3377de2362d3Smrg} 3378de2362d3Smrg#endif 3379de2362d3Smrg 3380de2362d3Smrgvoid drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3381de2362d3Smrg{ 3382de2362d3Smrg#ifdef HAVE_LIBUDEV 3383de2362d3Smrg struct udev *u; 3384de2362d3Smrg struct udev_monitor *mon; 3385de2362d3Smrg 3386de2362d3Smrg u = udev_new(); 3387de2362d3Smrg if (!u) 3388de2362d3Smrg return; 3389de2362d3Smrg mon = udev_monitor_new_from_netlink(u, "udev"); 3390de2362d3Smrg if (!mon) { 3391de2362d3Smrg udev_unref(u); 3392de2362d3Smrg return; 3393de2362d3Smrg } 3394de2362d3Smrg 3395de2362d3Smrg if (udev_monitor_filter_add_match_subsystem_devtype(mon, 3396de2362d3Smrg "drm", 3397de2362d3Smrg "drm_minor") < 0 || 3398de2362d3Smrg udev_monitor_enable_receiving(mon) < 0) { 3399de2362d3Smrg udev_monitor_unref(mon); 3400de2362d3Smrg udev_unref(u); 3401de2362d3Smrg return; 3402de2362d3Smrg } 3403de2362d3Smrg 3404de2362d3Smrg drmmode->uevent_handler = 3405de2362d3Smrg xf86AddGeneralHandler(udev_monitor_get_fd(mon), 3406de2362d3Smrg drmmode_handle_uevents, 3407de2362d3Smrg drmmode); 3408de2362d3Smrg 3409de2362d3Smrg drmmode->uevent_monitor = mon; 3410de2362d3Smrg#endif 3411de2362d3Smrg} 3412de2362d3Smrg 3413de2362d3Smrgvoid drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3414de2362d3Smrg{ 3415de2362d3Smrg#ifdef HAVE_LIBUDEV 3416de2362d3Smrg if (drmmode->uevent_handler) { 3417de2362d3Smrg struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); 3418de2362d3Smrg xf86RemoveGeneralHandler(drmmode->uevent_handler); 3419de2362d3Smrg 3420de2362d3Smrg udev_monitor_unref(drmmode->uevent_monitor); 3421de2362d3Smrg udev_unref(u); 3422de2362d3Smrg } 3423de2362d3Smrg#endif 3424de2362d3Smrg} 3425de2362d3Smrg 342618781e08SmrgBool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, 34278bf5c682Smrg PixmapPtr new_front, uint64_t id, void *data, 34288bf5c682Smrg xf86CrtcPtr ref_crtc, radeon_drm_handler_proc handler, 342918781e08Smrg radeon_drm_abort_proc abort, 34303ed65abbSmrg enum drmmode_flip_sync flip_sync, 34313ed65abbSmrg uint32_t target_msc) 3432de2362d3Smrg{ 34333ed65abbSmrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 3434de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 343518781e08Smrg xf86CrtcPtr crtc = NULL; 3436de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; 3437446f62d6Smrg int crtc_id; 34383ed65abbSmrg uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0; 3439de2362d3Smrg drmmode_flipdata_ptr flipdata; 344039413783Smrg Bool handle_deferred = FALSE; 344118781e08Smrg uintptr_t drm_queue_seq = 0; 344239413783Smrg struct drmmode_fb *fb; 344339413783Smrg int i = 0; 3444de2362d3Smrg 3445446f62d6Smrg flipdata = calloc(1, sizeof(*flipdata) + drmmode_crtc->drmmode->count_crtcs * 344639413783Smrg sizeof(flipdata->fb[0])); 34477821949aSmrg if (!flipdata) { 34487821949aSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 34497821949aSmrg "flip queue: data alloc failed.\n"); 345018781e08Smrg goto error; 34517821949aSmrg } 345218781e08Smrg 345339413783Smrg fb = radeon_pixmap_get_fb(new_front); 345439413783Smrg if (!fb) { 34558bf5c682Smrg ErrorF("Failed to get FB for flip\n"); 345618781e08Smrg goto error; 34578bf5c682Smrg } 345818781e08Smrg 3459de2362d3Smrg /* 3460de2362d3Smrg * Queue flips on all enabled CRTCs 3461de2362d3Smrg * Note that if/when we get per-CRTC buffers, we'll have to update this. 3462de2362d3Smrg * Right now it assumes a single shared fb across all CRTCs, with the 3463de2362d3Smrg * kernel fixing up the offset of each CRTC as necessary. 3464de2362d3Smrg * 3465de2362d3Smrg * Also, flips queued on disabled or incorrectly configured displays 3466de2362d3Smrg * may never complete; this is a configuration error. 3467de2362d3Smrg */ 3468de2362d3Smrg 3469de2362d3Smrg flipdata->event_data = data; 347018781e08Smrg flipdata->handler = handler; 347118781e08Smrg flipdata->abort = abort; 34728bf5c682Smrg flipdata->fe_crtc = ref_crtc; 347318781e08Smrg 3474de2362d3Smrg for (i = 0; i < config->num_crtc; i++) { 347518781e08Smrg crtc = config->crtc[i]; 34768bf5c682Smrg drmmode_crtc = crtc->driver_private; 3477446f62d6Smrg crtc_id = drmmode_get_crtc_id(crtc); 347818781e08Smrg 34798bf5c682Smrg if (!drmmode_crtc_can_flip(crtc) || 34808bf5c682Smrg (drmmode_crtc->tear_free && crtc != ref_crtc)) 3481de2362d3Smrg continue; 3482de2362d3Smrg 3483de2362d3Smrg flipdata->flip_count++; 348418781e08Smrg 348518781e08Smrg drm_queue_seq = radeon_drm_queue_alloc(crtc, client, id, 348618781e08Smrg flipdata, 348718781e08Smrg drmmode_flip_handler, 3488446f62d6Smrg drmmode_flip_abort, 3489446f62d6Smrg TRUE); 349018781e08Smrg if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { 349118781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 349218781e08Smrg "Allocating DRM queue event entry failed.\n"); 349318781e08Smrg goto error; 349418781e08Smrg } 3495de2362d3Smrg 34968bf5c682Smrg if (drmmode_crtc->tear_free) { 34978bf5c682Smrg BoxRec extents = { .x1 = 0, .y1 = 0, 34988bf5c682Smrg .x2 = new_front->drawable.width, 34998bf5c682Smrg .y2 = new_front->drawable.height }; 35008bf5c682Smrg int scanout_id = drmmode_crtc->scanout_id ^ 1; 35018bf5c682Smrg 35028bf5c682Smrg if (flip_sync == FLIP_ASYNC) { 35038bf5c682Smrg if (!drmmode_wait_vblank(crtc, 35048bf5c682Smrg DRM_VBLANK_RELATIVE | 35058bf5c682Smrg DRM_VBLANK_EVENT, 35068bf5c682Smrg 0, drm_queue_seq, 35078bf5c682Smrg NULL, NULL)) 35088bf5c682Smrg goto flip_error; 35098bf5c682Smrg goto next; 35108bf5c682Smrg } 35118bf5c682Smrg 3512446f62d6Smrg drmmode_fb_reference(pRADEONEnt->fd, &flipdata->fb[crtc_id], 351339413783Smrg radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap)); 3514446f62d6Smrg if (!flipdata->fb[crtc_id]) { 35158bf5c682Smrg ErrorF("Failed to get FB for TearFree flip\n"); 35168bf5c682Smrg goto error; 35178bf5c682Smrg } 35188bf5c682Smrg 35198bf5c682Smrg radeon_scanout_do_update(crtc, scanout_id, new_front, 352039413783Smrg extents); 352139413783Smrg radeon_cs_flush_indirect(crtc->scrn); 352239413783Smrg 352339413783Smrg if (drmmode_crtc->scanout_update_pending) { 352439413783Smrg radeon_drm_wait_pending_flip(crtc); 352539413783Smrg handle_deferred = TRUE; 352639413783Smrg radeon_drm_abort_entry(drmmode_crtc->scanout_update_pending); 352739413783Smrg drmmode_crtc->scanout_update_pending = 0; 352839413783Smrg } 352939413783Smrg } else { 3530446f62d6Smrg drmmode_fb_reference(pRADEONEnt->fd, &flipdata->fb[crtc_id], fb); 35318bf5c682Smrg } 35328bf5c682Smrg 35338bf5c682Smrg if (crtc == ref_crtc) { 35343ed65abbSmrg if (drmmode_page_flip_target_absolute(pRADEONEnt, 35353ed65abbSmrg drmmode_crtc, 3536446f62d6Smrg flipdata->fb[crtc_id]->handle, 35373ed65abbSmrg flip_flags, 35383ed65abbSmrg drm_queue_seq, 35393ed65abbSmrg target_msc) != 0) 35403ed65abbSmrg goto flip_error; 35413ed65abbSmrg } else { 35423ed65abbSmrg if (drmmode_page_flip_target_relative(pRADEONEnt, 35433ed65abbSmrg drmmode_crtc, 3544446f62d6Smrg flipdata->fb[crtc_id]->handle, 35453ed65abbSmrg flip_flags, 35463ed65abbSmrg drm_queue_seq, 0) != 0) 35473ed65abbSmrg goto flip_error; 3548de2362d3Smrg } 35493ed65abbSmrg 35508bf5c682Smrg if (drmmode_crtc->tear_free) { 35518bf5c682Smrg drmmode_crtc->scanout_id ^= 1; 35528bf5c682Smrg drmmode_crtc->ignore_damage = TRUE; 35538bf5c682Smrg } 35548bf5c682Smrg 355539413783Smrg drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->flip_pending, 3556446f62d6Smrg flipdata->fb[crtc_id]); 3557446f62d6Smrg 3558446f62d6Smrg next: 355918781e08Smrg drm_queue_seq = 0; 3560de2362d3Smrg } 3561de2362d3Smrg 356239413783Smrg if (handle_deferred) 356339413783Smrg radeon_drm_queue_handle_deferred(ref_crtc); 356418781e08Smrg if (flipdata->flip_count > 0) 356518781e08Smrg return TRUE; 35660d16fef4Smrg 35673ed65abbSmrgflip_error: 35683ed65abbSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n", 35693ed65abbSmrg strerror(errno)); 35703ed65abbSmrg 357118781e08Smrgerror: 357218781e08Smrg if (drm_queue_seq) 357318781e08Smrg radeon_drm_abort_entry(drm_queue_seq); 357418781e08Smrg else if (crtc) 357518781e08Smrg drmmode_flip_abort(crtc, flipdata); 35763ed65abbSmrg else { 35773ed65abbSmrg abort(NULL, data); 357818781e08Smrg free(flipdata); 35793ed65abbSmrg } 3580de2362d3Smrg 3581de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", 3582de2362d3Smrg strerror(errno)); 358339413783Smrg if (handle_deferred) 358439413783Smrg radeon_drm_queue_handle_deferred(ref_crtc); 3585de2362d3Smrg return FALSE; 3586de2362d3Smrg} 3587