drmmode_display.c revision 3ed65abb
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" 37de2362d3Smrg#include "micmap.h" 38de2362d3Smrg#include "xf86cmap.h" 3918781e08Smrg#include "xf86Priv.h" 40de2362d3Smrg#include "radeon.h" 4118781e08Smrg#include "radeon_bo_helper.h" 4218781e08Smrg#include "radeon_glamor.h" 4318781e08Smrg#include "radeon_list.h" 44de2362d3Smrg#include "radeon_reg.h" 4518781e08Smrg 4618781e08Smrg#ifdef RADEON_PIXMAP_SHARING 4718781e08Smrg#include <dri.h> 4818781e08Smrg#endif 49de2362d3Smrg 50de2362d3Smrg#include "drmmode_display.h" 51de2362d3Smrg 52de2362d3Smrg/* DPMS */ 53de2362d3Smrg#ifdef HAVE_XEXTPROTO_71 54de2362d3Smrg#include <X11/extensions/dpmsconst.h> 55de2362d3Smrg#else 56de2362d3Smrg#define DPMS_SERVER 57de2362d3Smrg#include <X11/extensions/dpms.h> 58de2362d3Smrg#endif 59de2362d3Smrg 6018781e08Smrg#define DEFAULT_NOMINAL_FRAME_RATE 60 6118781e08Smrg 6218781e08Smrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 22 6318781e08Smrg#define HAVE_NOTIFY_FD 1 6418781e08Smrg#endif 6518781e08Smrg 6618781e08Smrgstatic Bool 6718781e08Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height); 6818781e08Smrg 6918781e08Smrgstatic Bool 7018781e08SmrgRADEONZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name) 7118781e08Smrg{ 7218781e08Smrg int i = 0; 7318781e08Smrg char s1[20]; 7418781e08Smrg 7518781e08Smrg do { 7618781e08Smrg switch(*s) { 7718781e08Smrg case ',': 7818781e08Smrg s1[i] = '\0'; 7918781e08Smrg i = 0; 8018781e08Smrg if (strcmp(s1, output_name) == 0) 8118781e08Smrg return TRUE; 8218781e08Smrg break; 8318781e08Smrg case ' ': 8418781e08Smrg case '\t': 8518781e08Smrg case '\n': 8618781e08Smrg case '\r': 8718781e08Smrg break; 8818781e08Smrg default: 8918781e08Smrg s1[i] = *s; 9018781e08Smrg i++; 9118781e08Smrg break; 9218781e08Smrg } 9318781e08Smrg } while(*s++); 9418781e08Smrg 9518781e08Smrg s1[i] = '\0'; 9618781e08Smrg if (strcmp(s1, output_name) == 0) 9718781e08Smrg return TRUE; 9818781e08Smrg 9918781e08Smrg return FALSE; 10018781e08Smrg} 10118781e08Smrg 102de2362d3Smrgstatic PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn, 103de2362d3Smrg int width, int height, 104de2362d3Smrg int depth, int bpp, 10518781e08Smrg int pitch, 106de2362d3Smrg struct radeon_bo *bo, struct radeon_surface *psurf) 107de2362d3Smrg{ 108de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 109de2362d3Smrg ScreenPtr pScreen = pScrn->pScreen; 110de2362d3Smrg PixmapPtr pixmap; 111de2362d3Smrg struct radeon_surface *surface; 11218781e08Smrg uint32_t tiling; 113de2362d3Smrg 11418781e08Smrg pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 11518781e08Smrg RADEON_CREATE_PIXMAP_SCANOUT); 116de2362d3Smrg if (!pixmap) 117de2362d3Smrg return NULL; 118de2362d3Smrg 1197314432eSmrg if (!(*pScreen->ModifyPixmapHeader)(pixmap, width, height, 1207314432eSmrg depth, bpp, pitch, NULL)) { 12118781e08Smrg goto fail; 1227314432eSmrg } 1237314432eSmrg 12418781e08Smrg if (!info->use_glamor) 12518781e08Smrg exaMoveInPixmap(pixmap); 12618781e08Smrg 12718781e08Smrg if (!radeon_set_pixmap_bo(pixmap, bo)) 12818781e08Smrg goto fail; 12918781e08Smrg 130de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 131de2362d3Smrg surface = radeon_get_pixmap_surface(pixmap); 132de2362d3Smrg if (surface && psurf) 133de2362d3Smrg *surface = *psurf; 134de2362d3Smrg else if (surface) { 135de2362d3Smrg memset(surface, 0, sizeof(struct radeon_surface)); 136de2362d3Smrg surface->npix_x = width; 137de2362d3Smrg surface->npix_y = height; 138de2362d3Smrg surface->npix_z = 1; 139de2362d3Smrg surface->blk_w = 1; 140de2362d3Smrg surface->blk_h = 1; 141de2362d3Smrg surface->blk_d = 1; 142de2362d3Smrg surface->array_size = 1; 143de2362d3Smrg surface->last_level = 0; 144de2362d3Smrg surface->bpe = bpp / 8; 145de2362d3Smrg surface->nsamples = 1; 146de2362d3Smrg surface->flags = RADEON_SURF_SCANOUT; 14718781e08Smrg /* we are requiring a recent enough libdrm version */ 14818781e08Smrg surface->flags |= RADEON_SURF_HAS_TILE_MODE_INDEX; 149de2362d3Smrg surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); 150de2362d3Smrg surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR_ALIGNED, MODE); 15118781e08Smrg tiling = radeon_get_pixmap_tiling_flags(pixmap); 152de2362d3Smrg if (tiling & RADEON_TILING_MICRO) { 153de2362d3Smrg surface->flags = RADEON_SURF_CLR(surface->flags, MODE); 154de2362d3Smrg surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE); 155de2362d3Smrg } 156de2362d3Smrg if (tiling & RADEON_TILING_MACRO) { 157de2362d3Smrg surface->flags = RADEON_SURF_CLR(surface->flags, MODE); 158de2362d3Smrg surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE); 159de2362d3Smrg } 160de2362d3Smrg if (radeon_surface_best(info->surf_man, surface)) { 16118781e08Smrg goto fail; 162de2362d3Smrg } 163de2362d3Smrg if (radeon_surface_init(info->surf_man, surface)) { 16418781e08Smrg goto fail; 165de2362d3Smrg } 166de2362d3Smrg } 167de2362d3Smrg } 168de2362d3Smrg 16918781e08Smrg if (!info->use_glamor || 17018781e08Smrg radeon_glamor_create_textured_pixmap(pixmap, 17118781e08Smrg radeon_get_pixmap_private(pixmap))) 17218781e08Smrg return pixmap; 17318781e08Smrg 17418781e08Smrgfail: 17518781e08Smrg pScreen->DestroyPixmap(pixmap); 17618781e08Smrg return NULL; 177de2362d3Smrg} 178de2362d3Smrg 179de2362d3Smrgstatic void drmmode_destroy_bo_pixmap(PixmapPtr pixmap) 180de2362d3Smrg{ 181de2362d3Smrg ScreenPtr pScreen = pixmap->drawable.pScreen; 182de2362d3Smrg 183de2362d3Smrg (*pScreen->DestroyPixmap)(pixmap); 184de2362d3Smrg} 185de2362d3Smrg 186de2362d3Smrgstatic void 187de2362d3Smrgdrmmode_ConvertFromKMode(ScrnInfoPtr scrn, 188de2362d3Smrg drmModeModeInfo *kmode, 189de2362d3Smrg DisplayModePtr mode) 190de2362d3Smrg{ 191de2362d3Smrg memset(mode, 0, sizeof(DisplayModeRec)); 192de2362d3Smrg mode->status = MODE_OK; 193de2362d3Smrg 194de2362d3Smrg mode->Clock = kmode->clock; 195de2362d3Smrg 196de2362d3Smrg mode->HDisplay = kmode->hdisplay; 197de2362d3Smrg mode->HSyncStart = kmode->hsync_start; 198de2362d3Smrg mode->HSyncEnd = kmode->hsync_end; 199de2362d3Smrg mode->HTotal = kmode->htotal; 200de2362d3Smrg mode->HSkew = kmode->hskew; 201de2362d3Smrg 202de2362d3Smrg mode->VDisplay = kmode->vdisplay; 203de2362d3Smrg mode->VSyncStart = kmode->vsync_start; 204de2362d3Smrg mode->VSyncEnd = kmode->vsync_end; 205de2362d3Smrg mode->VTotal = kmode->vtotal; 206de2362d3Smrg mode->VScan = kmode->vscan; 207de2362d3Smrg 208de2362d3Smrg mode->Flags = kmode->flags; //& FLAG_BITS; 209de2362d3Smrg mode->name = strdup(kmode->name); 210de2362d3Smrg 211de2362d3Smrg if (kmode->type & DRM_MODE_TYPE_DRIVER) 212de2362d3Smrg mode->type = M_T_DRIVER; 213de2362d3Smrg if (kmode->type & DRM_MODE_TYPE_PREFERRED) 214de2362d3Smrg mode->type |= M_T_PREFERRED; 215de2362d3Smrg xf86SetModeCrtc (mode, scrn->adjustFlags); 216de2362d3Smrg} 217de2362d3Smrg 218de2362d3Smrgstatic void 219de2362d3Smrgdrmmode_ConvertToKMode(ScrnInfoPtr scrn, 220de2362d3Smrg drmModeModeInfo *kmode, 221de2362d3Smrg DisplayModePtr mode) 222de2362d3Smrg{ 223de2362d3Smrg memset(kmode, 0, sizeof(*kmode)); 224de2362d3Smrg 225de2362d3Smrg kmode->clock = mode->Clock; 226de2362d3Smrg kmode->hdisplay = mode->HDisplay; 227de2362d3Smrg kmode->hsync_start = mode->HSyncStart; 228de2362d3Smrg kmode->hsync_end = mode->HSyncEnd; 229de2362d3Smrg kmode->htotal = mode->HTotal; 230de2362d3Smrg kmode->hskew = mode->HSkew; 231de2362d3Smrg 232de2362d3Smrg kmode->vdisplay = mode->VDisplay; 233de2362d3Smrg kmode->vsync_start = mode->VSyncStart; 234de2362d3Smrg kmode->vsync_end = mode->VSyncEnd; 235de2362d3Smrg kmode->vtotal = mode->VTotal; 236de2362d3Smrg kmode->vscan = mode->VScan; 237de2362d3Smrg 238de2362d3Smrg kmode->flags = mode->Flags; //& FLAG_BITS; 239de2362d3Smrg if (mode->name) 240de2362d3Smrg strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); 241de2362d3Smrg kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0; 242de2362d3Smrg 243de2362d3Smrg} 244de2362d3Smrg 24518781e08Smrg/* 24618781e08Smrg * Retrieves present time in microseconds that is compatible 24718781e08Smrg * with units used by vblank timestamps. Depending on the kernel 24818781e08Smrg * version and DRM kernel module configuration, the vblank 24918781e08Smrg * timestamp can either be in real time or monotonic time 25018781e08Smrg */ 25118781e08Smrgint drmmode_get_current_ust(int drm_fd, CARD64 *ust) 25218781e08Smrg{ 25318781e08Smrg uint64_t cap_value; 25418781e08Smrg int ret; 25518781e08Smrg struct timespec now; 25618781e08Smrg 25718781e08Smrg ret = drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap_value); 25818781e08Smrg if (ret || !cap_value) 25918781e08Smrg /* old kernel or drm_timestamp_monotonic turned off */ 26018781e08Smrg ret = clock_gettime(CLOCK_REALTIME, &now); 26118781e08Smrg else 26218781e08Smrg ret = clock_gettime(CLOCK_MONOTONIC, &now); 26318781e08Smrg if (ret) 26418781e08Smrg return ret; 26518781e08Smrg *ust = ((CARD64)now.tv_sec * 1000000) + ((CARD64)now.tv_nsec / 1000); 26618781e08Smrg return 0; 26718781e08Smrg} 26818781e08Smrg 26918781e08Smrg/* 27018781e08Smrg * Get current frame count and frame count timestamp of the crtc. 27118781e08Smrg */ 27218781e08Smrgint drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc) 27318781e08Smrg{ 27418781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 27518781e08Smrg RADEONInfoPtr info = RADEONPTR(scrn); 27618781e08Smrg drmVBlank vbl; 27718781e08Smrg int ret; 27818781e08Smrg 27918781e08Smrg vbl.request.type = DRM_VBLANK_RELATIVE; 28018781e08Smrg vbl.request.type |= radeon_populate_vbl_request_type(crtc); 28118781e08Smrg vbl.request.sequence = 0; 28218781e08Smrg 28318781e08Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 28418781e08Smrg if (ret) { 28518781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 28618781e08Smrg "get vblank counter failed: %s\n", strerror(errno)); 28718781e08Smrg return ret; 28818781e08Smrg } 28918781e08Smrg 29018781e08Smrg *ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec; 29118781e08Smrg *msc = vbl.reply.sequence; 29218781e08Smrg 29318781e08Smrg return Success; 29418781e08Smrg} 29518781e08Smrg 296de2362d3Smrgstatic void 29718781e08Smrgdrmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode) 298de2362d3Smrg{ 299de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 30018781e08Smrg ScrnInfoPtr scrn = crtc->scrn; 30118781e08Smrg RADEONInfoPtr info = RADEONPTR(scrn); 30218781e08Smrg CARD64 ust; 30318781e08Smrg int ret; 3047314432eSmrg 30518781e08Smrg drmmode_crtc->pending_dpms_mode = mode; 3060d16fef4Smrg 30718781e08Smrg if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) { 30818781e08Smrg drmVBlank vbl; 30918781e08Smrg 31018781e08Smrg /* Wait for any pending flip to finish */ 31118781e08Smrg if (drmmode_crtc->flip_pending) 31218781e08Smrg return; 31318781e08Smrg 31418781e08Smrg /* 31518781e08Smrg * On->Off transition: record the last vblank time, 31618781e08Smrg * sequence number and frame period. 31718781e08Smrg */ 31818781e08Smrg vbl.request.type = DRM_VBLANK_RELATIVE; 31918781e08Smrg vbl.request.type |= radeon_populate_vbl_request_type(crtc); 32018781e08Smrg vbl.request.sequence = 0; 32118781e08Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 32218781e08Smrg if (ret) 32318781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 32418781e08Smrg "%s cannot get last vblank counter\n", 32518781e08Smrg __func__); 32618781e08Smrg else { 32718781e08Smrg CARD64 seq = (CARD64)vbl.reply.sequence; 32818781e08Smrg CARD64 nominal_frame_rate, pix_in_frame; 32918781e08Smrg 33018781e08Smrg ust = ((CARD64)vbl.reply.tval_sec * 1000000) + 33118781e08Smrg vbl.reply.tval_usec; 33218781e08Smrg drmmode_crtc->dpms_last_ust = ust; 33318781e08Smrg drmmode_crtc->dpms_last_seq = seq; 33418781e08Smrg nominal_frame_rate = crtc->mode.Clock; 33518781e08Smrg nominal_frame_rate *= 1000; 33618781e08Smrg pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal; 33718781e08Smrg if (nominal_frame_rate == 0 || pix_in_frame == 0) 33818781e08Smrg nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE; 33918781e08Smrg else 34018781e08Smrg nominal_frame_rate /= pix_in_frame; 34118781e08Smrg drmmode_crtc->dpms_last_fps = nominal_frame_rate; 34218781e08Smrg } 34318781e08Smrg } else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) { 34418781e08Smrg /* 34518781e08Smrg * Off->On transition: calculate and accumulate the 34618781e08Smrg * number of interpolated vblanks while we were in Off state 34718781e08Smrg */ 34818781e08Smrg ret = drmmode_get_current_ust(info->dri2.drm_fd, &ust); 34918781e08Smrg if (ret) 35018781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 35118781e08Smrg "%s cannot get current time\n", __func__); 35218781e08Smrg else if (drmmode_crtc->dpms_last_ust) { 35318781e08Smrg CARD64 time_elapsed, delta_seq; 35418781e08Smrg time_elapsed = ust - drmmode_crtc->dpms_last_ust; 35518781e08Smrg delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps; 35618781e08Smrg delta_seq /= 1000000; 35718781e08Smrg drmmode_crtc->interpolated_vblanks += delta_seq; 35818781e08Smrg 35918781e08Smrg } 3607821949aSmrg } 36118781e08Smrg drmmode_crtc->dpms_mode = mode; 36218781e08Smrg} 36318781e08Smrg 36418781e08Smrgstatic void 36518781e08Smrgdrmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) 36618781e08Smrg{ 36718781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 36818781e08Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 36918781e08Smrg 37018781e08Smrg /* Disable unused CRTCs */ 37118781e08Smrg if (!crtc->enabled || mode != DPMSModeOn) { 37218781e08Smrg /* Wait for any pending flip to finish */ 37318781e08Smrg if (drmmode_crtc->flip_pending) 37418781e08Smrg return; 37518781e08Smrg 37618781e08Smrg drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 37718781e08Smrg 0, 0, 0, NULL, 0, NULL); 37818781e08Smrg } else if (drmmode_crtc->dpms_mode != DPMSModeOn) 37918781e08Smrg crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, 38018781e08Smrg crtc->x, crtc->y); 381de2362d3Smrg} 382de2362d3Smrg 383de2362d3Smrgstatic PixmapPtr 384de2362d3Smrgcreate_pixmap_for_fbcon(drmmode_ptr drmmode, 385de2362d3Smrg ScrnInfoPtr pScrn, int fbcon_id) 386de2362d3Smrg{ 38718781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 38818781e08Smrg PixmapPtr pixmap = info->fbcon_pixmap; 389de2362d3Smrg struct radeon_bo *bo; 390de2362d3Smrg drmModeFBPtr fbcon; 391de2362d3Smrg struct drm_gem_flink flink; 392de2362d3Smrg 39318781e08Smrg if (pixmap) 39418781e08Smrg return pixmap; 39518781e08Smrg 396de2362d3Smrg fbcon = drmModeGetFB(drmmode->fd, fbcon_id); 397de2362d3Smrg if (fbcon == NULL) 398de2362d3Smrg return NULL; 399de2362d3Smrg 400de2362d3Smrg if (fbcon->depth != pScrn->depth || 401de2362d3Smrg fbcon->width != pScrn->virtualX || 402de2362d3Smrg fbcon->height != pScrn->virtualY) 403de2362d3Smrg goto out_free_fb; 404de2362d3Smrg 405de2362d3Smrg flink.handle = fbcon->handle; 406de2362d3Smrg if (ioctl(drmmode->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) { 407de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 408de2362d3Smrg "Couldn't flink fbcon handle\n"); 409de2362d3Smrg goto out_free_fb; 410de2362d3Smrg } 411de2362d3Smrg 412de2362d3Smrg bo = radeon_bo_open(drmmode->bufmgr, flink.name, 0, 0, 0, 0); 413de2362d3Smrg if (bo == NULL) { 414de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 415de2362d3Smrg "Couldn't allocate bo for fbcon handle\n"); 416de2362d3Smrg goto out_free_fb; 417de2362d3Smrg } 418de2362d3Smrg 419de2362d3Smrg pixmap = drmmode_create_bo_pixmap(pScrn, fbcon->width, fbcon->height, 42018781e08Smrg fbcon->depth, fbcon->bpp, fbcon->pitch, 42118781e08Smrg bo, NULL); 42218781e08Smrg info->fbcon_pixmap = pixmap; 423de2362d3Smrg radeon_bo_unref(bo); 424de2362d3Smrgout_free_fb: 425de2362d3Smrg drmModeFreeFB(fbcon); 426de2362d3Smrg return pixmap; 427de2362d3Smrg} 428de2362d3Smrg 42918781e08Smrgstatic void 43018781e08Smrgdestroy_pixmap_for_fbcon(ScrnInfoPtr pScrn) 43118781e08Smrg{ 43218781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 43318781e08Smrg 43418781e08Smrg /* XXX: The current GPUVM support in the kernel doesn't allow removing 43518781e08Smrg * the virtual address range for this BO, so we need to keep around 43618781e08Smrg * the pixmap to avoid breaking glamor with GPUVM 43718781e08Smrg */ 43818781e08Smrg if (info->use_glamor && info->ChipFamily >= CHIP_FAMILY_CAYMAN) 43918781e08Smrg return; 44018781e08Smrg 44118781e08Smrg if (info->fbcon_pixmap) 44218781e08Smrg pScrn->pScreen->DestroyPixmap(info->fbcon_pixmap); 44318781e08Smrg info->fbcon_pixmap = NULL; 44418781e08Smrg} 44518781e08Smrg 446de2362d3Smrgvoid drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 447de2362d3Smrg{ 448de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 449de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 450de2362d3Smrg PixmapPtr src, dst; 451de2362d3Smrg ScreenPtr pScreen = pScrn->pScreen; 452de2362d3Smrg int fbcon_id = 0; 45318781e08Smrg Bool force; 45418781e08Smrg GCPtr gc; 455de2362d3Smrg int i; 456de2362d3Smrg 457de2362d3Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 458de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private; 459de2362d3Smrg 460de2362d3Smrg if (drmmode_crtc->mode_crtc->buffer_id) 461de2362d3Smrg fbcon_id = drmmode_crtc->mode_crtc->buffer_id; 462de2362d3Smrg } 463de2362d3Smrg 464de2362d3Smrg if (!fbcon_id) 46518781e08Smrg return; 46618781e08Smrg 46718781e08Smrg if (fbcon_id == drmmode->fb_id) { 46818781e08Smrg /* in some rare case there might be no fbcon and we might already 46918781e08Smrg * be the one with the current fb to avoid a false deadlck in 47018781e08Smrg * kernel ttm code just do nothing as anyway there is nothing 47118781e08Smrg * to do 47218781e08Smrg */ 47318781e08Smrg return; 47418781e08Smrg } 475de2362d3Smrg 476de2362d3Smrg src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id); 477de2362d3Smrg if (!src) 47818781e08Smrg return; 4790d16fef4Smrg 48018781e08Smrg dst = pScreen->GetScreenPixmap(pScreen); 48118781e08Smrg 48218781e08Smrg gc = GetScratchGC(pScrn->depth, pScreen); 48318781e08Smrg ValidateGC(&dst->drawable, gc); 48418781e08Smrg 48518781e08Smrg force = info->accel_state->force; 48618781e08Smrg info->accel_state->force = TRUE; 48718781e08Smrg (*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0, 48818781e08Smrg pScrn->virtualX, pScrn->virtualY, 0, 0); 48918781e08Smrg info->accel_state->force = force; 49018781e08Smrg 49118781e08Smrg FreeScratchGC(gc); 492de2362d3Smrg 493de2362d3Smrg pScreen->canDoBGNoneRoot = TRUE; 49418781e08Smrg destroy_pixmap_for_fbcon(pScrn); 4957821949aSmrg return; 49618781e08Smrg} 4970d16fef4Smrg 49818781e08Smrgstatic void 49918781e08Smrgdrmmode_crtc_scanout_destroy(drmmode_ptr drmmode, 50018781e08Smrg struct drmmode_scanout *scanout) 50118781e08Smrg{ 50218781e08Smrg if (scanout->pixmap) { 50318781e08Smrg drmmode_destroy_bo_pixmap(scanout->pixmap); 50418781e08Smrg scanout->pixmap = NULL; 50518781e08Smrg } 50618781e08Smrg 50718781e08Smrg if (scanout->bo) { 50818781e08Smrg drmModeRmFB(drmmode->fd, scanout->fb_id); 50918781e08Smrg scanout->fb_id = 0; 51018781e08Smrg radeon_bo_unmap(scanout->bo); 51118781e08Smrg radeon_bo_unref(scanout->bo); 51218781e08Smrg scanout->bo = NULL; 51318781e08Smrg } 51418781e08Smrg} 51518781e08Smrg 51618781e08Smrgstatic void 51718781e08Smrgdrmmode_crtc_scanout_free(drmmode_crtc_private_ptr drmmode_crtc) 51818781e08Smrg{ 51918781e08Smrg if (drmmode_crtc->flip_pending) { 52018781e08Smrg drmmode_crtc->scanout_destroy[0] = drmmode_crtc->scanout[0]; 52118781e08Smrg drmmode_crtc->scanout[0].pixmap = NULL; 52218781e08Smrg drmmode_crtc->scanout[0].bo = NULL; 52318781e08Smrg drmmode_crtc->scanout_destroy[1] = drmmode_crtc->scanout[1]; 52418781e08Smrg drmmode_crtc->scanout[1].pixmap = NULL; 52518781e08Smrg drmmode_crtc->scanout[1].bo = NULL; 52618781e08Smrg } else { 52718781e08Smrg drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 52818781e08Smrg &drmmode_crtc->scanout[0]); 52918781e08Smrg drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 53018781e08Smrg &drmmode_crtc->scanout[1]); 53118781e08Smrg } 53218781e08Smrg 53318781e08Smrg if (drmmode_crtc->scanout_damage) { 53418781e08Smrg DamageDestroy(drmmode_crtc->scanout_damage); 53518781e08Smrg drmmode_crtc->scanout_damage = NULL; 53618781e08Smrg RegionUninit(&drmmode_crtc->scanout_last_region); 53718781e08Smrg } 53818781e08Smrg} 53918781e08Smrg 54018781e08Smrgvoid 54118781e08Smrgdrmmode_scanout_free(ScrnInfoPtr scrn) 54218781e08Smrg{ 54318781e08Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 54418781e08Smrg int c; 54518781e08Smrg 54618781e08Smrg for (c = 0; c < xf86_config->num_crtc; c++) 54718781e08Smrg drmmode_crtc_scanout_free(xf86_config->crtc[c]->driver_private); 54818781e08Smrg} 54918781e08Smrg 5503ed65abbSmrgstatic PixmapPtr 5513ed65abbSmrgdrmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout, 5523ed65abbSmrg int width, int height) 55318781e08Smrg{ 55418781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 55518781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 55618781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 55718781e08Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 55818781e08Smrg struct radeon_surface surface; 55918781e08Smrg uint32_t tiling = RADEON_CREATE_PIXMAP_TILING_MACRO; 56018781e08Smrg int pitch; 56118781e08Smrg 5623ed65abbSmrg if (scanout->pixmap) { 56318781e08Smrg if (scanout->width == width && scanout->height == height) 5643ed65abbSmrg return scanout->pixmap; 56518781e08Smrg 56618781e08Smrg drmmode_crtc_scanout_destroy(drmmode, scanout); 56718781e08Smrg } 56818781e08Smrg 56918781e08Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) 57018781e08Smrg tiling |= RADEON_CREATE_PIXMAP_TILING_MICRO; 57118781e08Smrg scanout->bo = radeon_alloc_pixmap_bo(pScrn, width, height, pScrn->depth, 57218781e08Smrg tiling, pScrn->bitsPerPixel, 57318781e08Smrg &pitch, &surface, &tiling); 57418781e08Smrg if (scanout->bo == NULL) 5753ed65abbSmrg goto error; 57618781e08Smrg 5773ed65abbSmrg if (drmModeAddFB(drmmode->fd, width, height, pScrn->depth, 57818781e08Smrg pScrn->bitsPerPixel, pitch, 57918781e08Smrg scanout->bo->handle, 5803ed65abbSmrg &scanout->fb_id) != 0) { 58118781e08Smrg ErrorF("failed to add scanout fb\n"); 5823ed65abbSmrg goto error; 58318781e08Smrg } 58418781e08Smrg 58518781e08Smrg scanout->pixmap = drmmode_create_bo_pixmap(pScrn, 58618781e08Smrg width, height, 58718781e08Smrg pScrn->depth, 58818781e08Smrg pScrn->bitsPerPixel, 5893ed65abbSmrg pitch, scanout->bo, NULL); 5903ed65abbSmrg if (scanout->pixmap) { 5913ed65abbSmrg scanout->width = width; 5923ed65abbSmrg scanout->height = height; 5933ed65abbSmrg } else { 59418781e08Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 59518781e08Smrg "Couldn't allocate scanout pixmap for CRTC\n"); 5963ed65abbSmrgerror: 5973ed65abbSmrg drmmode_crtc_scanout_destroy(drmmode, scanout); 5983ed65abbSmrg } 59918781e08Smrg 60018781e08Smrg return scanout->pixmap; 60118781e08Smrg} 60218781e08Smrg 60318781e08Smrgstatic void 60418781e08Smrgradeon_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure) 60518781e08Smrg{ 60618781e08Smrg /* Only keep track of the extents */ 60718781e08Smrg RegionUninit(&damage->damage); 60818781e08Smrg damage->damage.data = NULL; 60918781e08Smrg} 61018781e08Smrg 61118781e08Smrgstatic Bool 61218781e08Smrgdrmmode_can_use_hw_cursor(xf86CrtcPtr crtc) 61318781e08Smrg{ 61418781e08Smrg RADEONInfoPtr info = RADEONPTR(crtc->scrn); 61518781e08Smrg 61618781e08Smrg /* Check for Option "SWcursor" */ 61718781e08Smrg if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) 61818781e08Smrg return FALSE; 61918781e08Smrg 62018781e08Smrg /* Fall back to SW cursor if the CRTC is transformed */ 62118781e08Smrg if (crtc->transformPresent) 62218781e08Smrg return FALSE; 6230d16fef4Smrg 62418781e08Smrg#if XF86_CRTC_VERSION >= 4 && XF86_CRTC_VERSION < 7 62518781e08Smrg /* Xorg doesn't correctly handle cursor position transform in the 62618781e08Smrg * rotation case 62718781e08Smrg */ 62818781e08Smrg if (crtc->driverIsPerformingTransform && 62918781e08Smrg (crtc->rotation & 0xf) != RR_Rotate_0) 63018781e08Smrg return FALSE; 63118781e08Smrg#endif 63218781e08Smrg 63318781e08Smrg#if defined(RADEON_PIXMAP_SHARING) 63418781e08Smrg /* HW cursor not supported with RandR 1.4 multihead up to 1.18.99.901 */ 63518781e08Smrg if (xorgGetVersion() <= XORG_VERSION_NUMERIC(1,18,99,901,0) && 63618781e08Smrg !xorg_list_is_empty(&crtc->scrn->pScreen->pixmap_dirty_list)) 63718781e08Smrg return FALSE; 63818781e08Smrg#endif 63918781e08Smrg 64018781e08Smrg return TRUE; 64118781e08Smrg} 64218781e08Smrg 6433ed65abbSmrgstatic void 6443ed65abbSmrgdrmmode_crtc_update_tear_free(xf86CrtcPtr crtc) 6453ed65abbSmrg{ 6463ed65abbSmrg RADEONInfoPtr info = RADEONPTR(crtc->scrn); 6473ed65abbSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 6483ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 6493ed65abbSmrg int i; 6503ed65abbSmrg 6513ed65abbSmrg drmmode_crtc->tear_free = FALSE; 6523ed65abbSmrg 6533ed65abbSmrg for (i = 0; i < xf86_config->num_output; i++) { 6543ed65abbSmrg xf86OutputPtr output = xf86_config->output[i]; 6553ed65abbSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 6563ed65abbSmrg 6573ed65abbSmrg if (output->crtc != crtc) 6583ed65abbSmrg continue; 6593ed65abbSmrg 6603ed65abbSmrg if (drmmode_output->tear_free == 1 || 6613ed65abbSmrg (drmmode_output->tear_free == 2 && 6623ed65abbSmrg (radeon_is_gpu_screen(crtc->scrn->pScreen) || 6633ed65abbSmrg info->shadow_primary || 6643ed65abbSmrg crtc->transformPresent || crtc->rotation != RR_Rotate_0))) { 6653ed65abbSmrg drmmode_crtc->tear_free = TRUE; 6663ed65abbSmrg return; 6673ed65abbSmrg } 6683ed65abbSmrg } 6693ed65abbSmrg} 6703ed65abbSmrg 67118781e08Smrg#if XF86_CRTC_VERSION >= 4 67218781e08Smrg 6733ed65abbSmrg#if XF86_CRTC_VERSION < 7 6743ed65abbSmrg#define XF86DriverTransformOutput TRUE 6753ed65abbSmrg#define XF86DriverTransformNone FALSE 6763ed65abbSmrg#endif 6773ed65abbSmrg 67818781e08Smrgstatic Bool 67918781e08Smrgdrmmode_handle_transform(xf86CrtcPtr crtc) 68018781e08Smrg{ 68118781e08Smrg Bool ret; 68218781e08Smrg 68318781e08Smrg if (crtc->transformPresent || crtc->rotation != RR_Rotate_0) 68418781e08Smrg crtc->driverIsPerformingTransform = XF86DriverTransformOutput; 68518781e08Smrg else 68618781e08Smrg crtc->driverIsPerformingTransform = XF86DriverTransformNone; 68718781e08Smrg 68818781e08Smrg ret = xf86CrtcRotate(crtc); 68918781e08Smrg 69018781e08Smrg crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use; 69118781e08Smrg 69218781e08Smrg return ret; 6930d16fef4Smrg} 6940d16fef4Smrg 69518781e08Smrg#else 69618781e08Smrg 69718781e08Smrgstatic Bool 69818781e08Smrgdrmmode_handle_transform(xf86CrtcPtr crtc) 69918781e08Smrg{ 70018781e08Smrg return xf86CrtcRotate(crtc); 70118781e08Smrg} 70218781e08Smrg 70318781e08Smrg#endif 70418781e08Smrg 7053ed65abbSmrg#ifdef RADEON_PIXMAP_SHARING 7063ed65abbSmrg 7073ed65abbSmrgstatic void 7083ed65abbSmrgdrmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, 7093ed65abbSmrg unsigned scanout_id, int *fb_id, int *x, 7103ed65abbSmrg int *y) 7113ed65abbSmrg{ 7123ed65abbSmrg ScrnInfoPtr scrn = crtc->scrn; 7133ed65abbSmrg ScreenPtr screen = scrn->pScreen; 7143ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 7153ed65abbSmrg 7163ed65abbSmrg if (drmmode_crtc->tear_free && 7173ed65abbSmrg !drmmode_crtc->scanout[1].pixmap) { 7183ed65abbSmrg RegionPtr region; 7193ed65abbSmrg BoxPtr box; 7203ed65abbSmrg 7213ed65abbSmrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 7223ed65abbSmrg mode->HDisplay, 7233ed65abbSmrg mode->VDisplay); 7243ed65abbSmrg region = &drmmode_crtc->scanout_last_region; 7253ed65abbSmrg RegionUninit(region); 7263ed65abbSmrg region->data = NULL; 7273ed65abbSmrg box = RegionExtents(region); 7283ed65abbSmrg box->x1 = crtc->x; 7293ed65abbSmrg box->y1 = crtc->y; 7303ed65abbSmrg box->x2 = crtc->x + mode->HDisplay; 7313ed65abbSmrg box->y2 = crtc->y + mode->VDisplay; 7323ed65abbSmrg } 7333ed65abbSmrg 7343ed65abbSmrg if (scanout_id != drmmode_crtc->scanout_id) { 7353ed65abbSmrg PixmapDirtyUpdatePtr dirty = NULL; 7363ed65abbSmrg 7373ed65abbSmrg xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, 7383ed65abbSmrg ent) { 7393ed65abbSmrg if (dirty->src == crtc->randr_crtc->scanout_pixmap && 7403ed65abbSmrg dirty->slave_dst == 7413ed65abbSmrg drmmode_crtc->scanout[drmmode_crtc->scanout_id].pixmap) { 7423ed65abbSmrg dirty->slave_dst = 7433ed65abbSmrg drmmode_crtc->scanout[scanout_id].pixmap; 7443ed65abbSmrg break; 7453ed65abbSmrg } 7463ed65abbSmrg } 7473ed65abbSmrg 7483ed65abbSmrg if (!drmmode_crtc->tear_free) { 7493ed65abbSmrg GCPtr gc = GetScratchGC(scrn->depth, screen); 7503ed65abbSmrg 7513ed65abbSmrg ValidateGC(&drmmode_crtc->scanout[0].pixmap->drawable, gc); 7523ed65abbSmrg gc->ops->CopyArea(&drmmode_crtc->scanout[1].pixmap->drawable, 7533ed65abbSmrg &drmmode_crtc->scanout[0].pixmap->drawable, 7543ed65abbSmrg gc, 0, 0, mode->HDisplay, mode->VDisplay, 7553ed65abbSmrg 0, 0); 7563ed65abbSmrg FreeScratchGC(gc); 7573ed65abbSmrg radeon_cs_flush_indirect(scrn); 7583ed65abbSmrg radeon_bo_wait(drmmode_crtc->scanout[0].bo); 7593ed65abbSmrg } 7603ed65abbSmrg } 7613ed65abbSmrg 7623ed65abbSmrg *fb_id = drmmode_crtc->scanout[scanout_id].fb_id; 7633ed65abbSmrg *x = *y = 0; 7643ed65abbSmrg drmmode_crtc->scanout_id = scanout_id; 7653ed65abbSmrg} 7663ed65abbSmrg 7673ed65abbSmrg#endif /* RADEON_PIXMAP_SHARING */ 7683ed65abbSmrg 7693ed65abbSmrgstatic void 7703ed65abbSmrgdrmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, 7713ed65abbSmrg unsigned scanout_id, int *fb_id, int *x, int *y) 7723ed65abbSmrg{ 7733ed65abbSmrg ScrnInfoPtr scrn = crtc->scrn; 7743ed65abbSmrg ScreenPtr screen = scrn->pScreen; 7753ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 7763ed65abbSmrg 7773ed65abbSmrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0], 7783ed65abbSmrg mode->HDisplay, mode->VDisplay); 7793ed65abbSmrg if (drmmode_crtc->tear_free) { 7803ed65abbSmrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 7813ed65abbSmrg mode->HDisplay, mode->VDisplay); 7823ed65abbSmrg } 7833ed65abbSmrg 7843ed65abbSmrg if (drmmode_crtc->scanout[0].pixmap && 7853ed65abbSmrg (!drmmode_crtc->tear_free || drmmode_crtc->scanout[1].pixmap)) { 7863ed65abbSmrg RegionPtr region; 7873ed65abbSmrg BoxPtr box; 7883ed65abbSmrg 7893ed65abbSmrg if (!drmmode_crtc->scanout_damage) { 7903ed65abbSmrg drmmode_crtc->scanout_damage = 7913ed65abbSmrg DamageCreate(radeon_screen_damage_report, 7923ed65abbSmrg NULL, DamageReportRawRegion, 7933ed65abbSmrg TRUE, screen, NULL); 7943ed65abbSmrg DamageRegister(&screen->GetScreenPixmap(screen)->drawable, 7953ed65abbSmrg drmmode_crtc->scanout_damage); 7963ed65abbSmrg } 7973ed65abbSmrg 7983ed65abbSmrg region = DamageRegion(drmmode_crtc->scanout_damage); 7993ed65abbSmrg RegionUninit(region); 8003ed65abbSmrg region->data = NULL; 8013ed65abbSmrg box = RegionExtents(region); 8023ed65abbSmrg box->x1 = 0; 8033ed65abbSmrg box->y1 = 0; 8043ed65abbSmrg box->x2 = max(box->x2, scrn->virtualX); 8053ed65abbSmrg box->y2 = max(box->y2, scrn->virtualY); 8063ed65abbSmrg 8073ed65abbSmrg *fb_id = drmmode_crtc->scanout[scanout_id].fb_id; 8083ed65abbSmrg *x = *y = 0; 8093ed65abbSmrg 8103ed65abbSmrg radeon_scanout_do_update(crtc, scanout_id); 8113ed65abbSmrg radeon_bo_wait(drmmode_crtc->scanout[scanout_id].bo); 8123ed65abbSmrg } 8133ed65abbSmrg} 8143ed65abbSmrg 815de2362d3Smrgstatic Bool 816de2362d3Smrgdrmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 817de2362d3Smrg Rotation rotation, int x, int y) 818de2362d3Smrg{ 819de2362d3Smrg ScrnInfoPtr pScrn = crtc->scrn; 82018781e08Smrg ScreenPtr pScreen = pScrn->pScreen; 821de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 822de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 823de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 8243ed65abbSmrg unsigned scanout_id = 0; 825de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 826de2362d3Smrg int saved_x, saved_y; 827de2362d3Smrg Rotation saved_rotation; 828de2362d3Smrg DisplayModeRec saved_mode; 82918781e08Smrg uint32_t *output_ids = NULL; 830de2362d3Smrg int output_count = 0; 83118781e08Smrg Bool ret = FALSE; 832de2362d3Smrg int i; 833de2362d3Smrg int fb_id; 834de2362d3Smrg drmModeModeInfo kmode; 835de2362d3Smrg 836de2362d3Smrg saved_mode = crtc->mode; 837de2362d3Smrg saved_x = crtc->x; 838de2362d3Smrg saved_y = crtc->y; 839de2362d3Smrg saved_rotation = crtc->rotation; 840de2362d3Smrg 841de2362d3Smrg if (mode) { 842de2362d3Smrg crtc->mode = *mode; 843de2362d3Smrg crtc->x = x; 844de2362d3Smrg crtc->y = y; 845de2362d3Smrg crtc->rotation = rotation; 846de2362d3Smrg 84718781e08Smrg output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); 84818781e08Smrg if (!output_ids) 84918781e08Smrg goto done; 850de2362d3Smrg 851de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 852de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 853de2362d3Smrg drmmode_output_private_ptr drmmode_output; 854de2362d3Smrg 855de2362d3Smrg if (output->crtc != crtc) 856de2362d3Smrg continue; 857de2362d3Smrg 858de2362d3Smrg drmmode_output = output->driver_private; 859de2362d3Smrg output_ids[output_count] = drmmode_output->mode_output->connector_id; 860de2362d3Smrg output_count++; 861de2362d3Smrg } 862de2362d3Smrg 86318781e08Smrg if (!drmmode_handle_transform(crtc)) 864de2362d3Smrg goto done; 86518781e08Smrg 8663ed65abbSmrg drmmode_crtc_update_tear_free(crtc); 8673ed65abbSmrg if (drmmode_crtc->tear_free) 8683ed65abbSmrg scanout_id = drmmode_crtc->scanout_id; 8693ed65abbSmrg 870de2362d3Smrg crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, 871de2362d3Smrg crtc->gamma_blue, crtc->gamma_size); 87218781e08Smrg 873de2362d3Smrg drmmode_ConvertToKMode(crtc->scrn, &kmode, mode); 874de2362d3Smrg 875de2362d3Smrg fb_id = drmmode->fb_id; 87618781e08Smrg#ifdef RADEON_PIXMAP_SHARING 87718781e08Smrg if (crtc->randr_crtc && crtc->randr_crtc->scanout_pixmap) { 8783ed65abbSmrg drmmode_crtc_prime_scanout_update(crtc, mode, scanout_id, 8793ed65abbSmrg &fb_id, &x, &y); 88018781e08Smrg } else 88118781e08Smrg#endif 88218781e08Smrg if (drmmode_crtc->rotate.fb_id) { 88318781e08Smrg fb_id = drmmode_crtc->rotate.fb_id; 88418781e08Smrg x = y = 0; 88518781e08Smrg 8863ed65abbSmrg } else if (!radeon_is_gpu_screen(pScreen) && 8873ed65abbSmrg (drmmode_crtc->tear_free || 88818781e08Smrg#if XF86_CRTC_VERSION >= 4 88918781e08Smrg crtc->driverIsPerformingTransform || 89018781e08Smrg#endif 89118781e08Smrg info->shadow_primary)) { 8923ed65abbSmrg drmmode_crtc_scanout_update(crtc, mode, scanout_id, 8933ed65abbSmrg &fb_id, &x, &y); 894de2362d3Smrg } 89518781e08Smrg 89618781e08Smrg if (fb_id == 0) { 89718781e08Smrg if (drmModeAddFB(drmmode->fd, 89818781e08Smrg pScrn->virtualX, 89918781e08Smrg pScrn->virtualY, 90018781e08Smrg pScrn->depth, pScrn->bitsPerPixel, 90118781e08Smrg pScrn->displayWidth * info->pixel_bytes, 90218781e08Smrg info->front_bo->handle, 90318781e08Smrg &drmmode->fb_id) < 0) { 90418781e08Smrg ErrorF("failed to add fb\n"); 90518781e08Smrg goto done; 90618781e08Smrg } 90718781e08Smrg 90818781e08Smrg fb_id = drmmode->fb_id; 90918781e08Smrg } 91018781e08Smrg 91118781e08Smrg /* Wait for any pending flip to finish */ 91218781e08Smrg do {} while (drmmode_crtc->flip_pending && 91318781e08Smrg drmHandleEvent(drmmode->fd, 91418781e08Smrg &drmmode->event_context) > 0); 91518781e08Smrg 91618781e08Smrg if (drmModeSetCrtc(drmmode->fd, 91718781e08Smrg drmmode_crtc->mode_crtc->crtc_id, 91818781e08Smrg fb_id, x, y, output_ids, 91918781e08Smrg output_count, &kmode) != 0) { 920de2362d3Smrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 92118781e08Smrg "failed to set mode: %s\n", strerror(errno)); 92218781e08Smrg goto done; 92318781e08Smrg } else 924de2362d3Smrg ret = TRUE; 925de2362d3Smrg 92618781e08Smrg if (pScreen) 92718781e08Smrg xf86CrtcSetScreenSubpixelOrder(pScreen); 92818781e08Smrg 92918781e08Smrg drmmode_crtc->need_modeset = FALSE; 93018781e08Smrg 931de2362d3Smrg /* go through all the outputs and force DPMS them back on? */ 932de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 933de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 934de2362d3Smrg 935de2362d3Smrg if (output->crtc != crtc) 936de2362d3Smrg continue; 937de2362d3Smrg 938de2362d3Smrg output->funcs->dpms(output, DPMSModeOn); 939de2362d3Smrg } 940de2362d3Smrg } 941de2362d3Smrg 94218781e08Smrg /* Compute index of this CRTC into xf86_config->crtc */ 94318781e08Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 94418781e08Smrg if (xf86_config->crtc[i] != crtc) 94518781e08Smrg continue; 94618781e08Smrg 94718781e08Smrg if (!crtc->enabled || drmmode_can_use_hw_cursor(crtc)) 94818781e08Smrg info->hwcursor_disabled &= ~(1 << i); 94918781e08Smrg else 95018781e08Smrg info->hwcursor_disabled |= 1 << i; 95118781e08Smrg 95218781e08Smrg break; 95318781e08Smrg } 95418781e08Smrg 95518781e08Smrg#ifndef HAVE_XF86_CURSOR_RESET_CURSOR 95618781e08Smrg if (!info->hwcursor_disabled) 95718781e08Smrg xf86_reload_cursors(pScreen); 95818781e08Smrg#endif 959de2362d3Smrg 960de2362d3Smrgdone: 961de2362d3Smrg if (!ret) { 962de2362d3Smrg crtc->x = saved_x; 963de2362d3Smrg crtc->y = saved_y; 964de2362d3Smrg crtc->rotation = saved_rotation; 965de2362d3Smrg crtc->mode = saved_mode; 96618781e08Smrg } else { 9677821949aSmrg crtc->active = TRUE; 96818781e08Smrg 9693ed65abbSmrg if (fb_id != drmmode_crtc->scanout[scanout_id].fb_id) 97018781e08Smrg drmmode_crtc_scanout_free(drmmode_crtc); 9713ed65abbSmrg else if (!drmmode_crtc->tear_free) { 9723ed65abbSmrg drmmode_crtc_scanout_destroy(drmmode, 9733ed65abbSmrg &drmmode_crtc->scanout[1]); 9743ed65abbSmrg } 97518781e08Smrg } 97618781e08Smrg 97718781e08Smrg free(output_ids); 978de2362d3Smrg 979de2362d3Smrg return ret; 980de2362d3Smrg} 981de2362d3Smrg 982de2362d3Smrgstatic void 983de2362d3Smrgdrmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg) 984de2362d3Smrg{ 985de2362d3Smrg 986de2362d3Smrg} 987de2362d3Smrg 988de2362d3Smrgstatic void 989de2362d3Smrgdrmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y) 990de2362d3Smrg{ 991de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 992de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 993de2362d3Smrg 99418781e08Smrg#if XF86_CRTC_VERSION >= 4 && XF86_CRTC_VERSION < 7 99518781e08Smrg if (crtc->driverIsPerformingTransform) { 99618781e08Smrg x += crtc->x; 99718781e08Smrg y += crtc->y; 99818781e08Smrg xf86CrtcTransformCursorPos(crtc, &x, &y); 99918781e08Smrg } 100018781e08Smrg#endif 100118781e08Smrg 1002de2362d3Smrg drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); 1003de2362d3Smrg} 1004de2362d3Smrg 100518781e08Smrg#if XF86_CRTC_VERSION >= 4 && XF86_CRTC_VERSION < 7 100618781e08Smrg 100718781e08Smrgstatic int 100818781e08Smrgdrmmode_cursor_src_offset(Rotation rotation, int width, int height, 100918781e08Smrg int x_dst, int y_dst) 101018781e08Smrg{ 101118781e08Smrg int t; 101218781e08Smrg 101318781e08Smrg switch (rotation & 0xf) { 101418781e08Smrg case RR_Rotate_90: 101518781e08Smrg t = x_dst; 101618781e08Smrg x_dst = height - y_dst - 1; 101718781e08Smrg y_dst = t; 101818781e08Smrg break; 101918781e08Smrg case RR_Rotate_180: 102018781e08Smrg x_dst = width - x_dst - 1; 102118781e08Smrg y_dst = height - y_dst - 1; 102218781e08Smrg break; 102318781e08Smrg case RR_Rotate_270: 102418781e08Smrg t = x_dst; 102518781e08Smrg x_dst = y_dst; 102618781e08Smrg y_dst = width - t - 1; 102718781e08Smrg break; 102818781e08Smrg } 102918781e08Smrg 103018781e08Smrg if (rotation & RR_Reflect_X) 103118781e08Smrg x_dst = width - x_dst - 1; 103218781e08Smrg if (rotation & RR_Reflect_Y) 103318781e08Smrg y_dst = height - y_dst - 1; 103418781e08Smrg 103518781e08Smrg return y_dst * height + x_dst; 103618781e08Smrg} 103718781e08Smrg 103818781e08Smrg#endif 103918781e08Smrg 1040de2362d3Smrgstatic void 1041de2362d3Smrgdrmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image) 1042de2362d3Smrg{ 104318781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 104418781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1045de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1046de2362d3Smrg uint32_t *ptr; 1047de2362d3Smrg 1048de2362d3Smrg /* cursor should be mapped already */ 1049de2362d3Smrg ptr = (uint32_t *)(drmmode_crtc->cursor_bo->ptr); 1050de2362d3Smrg 105118781e08Smrg#if XF86_CRTC_VERSION >= 4 && XF86_CRTC_VERSION < 7 105218781e08Smrg if (crtc->driverIsPerformingTransform) { 105318781e08Smrg uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h; 105418781e08Smrg int dstx, dsty; 105518781e08Smrg int srcoffset; 105618781e08Smrg 105718781e08Smrg for (dsty = 0; dsty < cursor_h; dsty++) { 105818781e08Smrg for (dstx = 0; dstx < cursor_w; dstx++) { 105918781e08Smrg srcoffset = drmmode_cursor_src_offset(crtc->rotation, 106018781e08Smrg cursor_w, 106118781e08Smrg cursor_h, 106218781e08Smrg dstx, dsty); 106318781e08Smrg 106418781e08Smrg ptr[dsty * info->cursor_w + dstx] = 106518781e08Smrg cpu_to_le32(image[srcoffset]); 106618781e08Smrg } 106718781e08Smrg } 106818781e08Smrg } else 106918781e08Smrg#endif 107018781e08Smrg { 107118781e08Smrg uint32_t cursor_size = info->cursor_w * info->cursor_h; 107218781e08Smrg int i; 107318781e08Smrg 107418781e08Smrg for (i = 0; i < cursor_size; i++) 107518781e08Smrg ptr[i] = cpu_to_le32(image[i]); 107618781e08Smrg } 1077de2362d3Smrg} 1078de2362d3Smrg 107918781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 108018781e08Smrg 108118781e08Smrgstatic Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image) 108218781e08Smrg{ 108318781e08Smrg if (!drmmode_can_use_hw_cursor(crtc)) 108418781e08Smrg return FALSE; 108518781e08Smrg 108618781e08Smrg drmmode_load_cursor_argb(crtc, image); 108718781e08Smrg return TRUE; 108818781e08Smrg} 108918781e08Smrg 109018781e08Smrg#endif 1091de2362d3Smrg 1092de2362d3Smrgstatic void 1093de2362d3Smrgdrmmode_hide_cursor (xf86CrtcPtr crtc) 1094de2362d3Smrg{ 109518781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 109618781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1097de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1098de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 1099de2362d3Smrg 110018781e08Smrg drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 110118781e08Smrg info->cursor_w, info->cursor_h); 1102de2362d3Smrg 1103de2362d3Smrg} 1104de2362d3Smrg 1105de2362d3Smrgstatic void 1106de2362d3Smrgdrmmode_show_cursor (xf86CrtcPtr crtc) 1107de2362d3Smrg{ 110818781e08Smrg ScrnInfoPtr pScrn = crtc->scrn; 110918781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1110de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1111de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 1112de2362d3Smrg uint32_t handle = drmmode_crtc->cursor_bo->handle; 111318781e08Smrg static Bool use_set_cursor2 = TRUE; 111418781e08Smrg 111518781e08Smrg if (use_set_cursor2) { 111618781e08Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 111718781e08Smrg CursorPtr cursor = xf86_config->cursor; 111818781e08Smrg int xhot = cursor->bits->xhot; 111918781e08Smrg int yhot = cursor->bits->yhot; 112018781e08Smrg int ret; 112118781e08Smrg 112218781e08Smrg if (crtc->rotation != RR_Rotate_0 && 112318781e08Smrg crtc->rotation != (RR_Rotate_180 | RR_Reflect_X | 112418781e08Smrg RR_Reflect_Y)) { 112518781e08Smrg int t; 112618781e08Smrg 112718781e08Smrg /* Reflect & rotate hotspot position */ 112818781e08Smrg if (crtc->rotation & RR_Reflect_X) 112918781e08Smrg xhot = info->cursor_w - xhot - 1; 113018781e08Smrg if (crtc->rotation & RR_Reflect_Y) 113118781e08Smrg yhot = info->cursor_h - yhot - 1; 113218781e08Smrg 113318781e08Smrg switch (crtc->rotation & 0xf) { 113418781e08Smrg case RR_Rotate_90: 113518781e08Smrg t = xhot; 113618781e08Smrg xhot = yhot; 113718781e08Smrg yhot = info->cursor_w - t - 1; 113818781e08Smrg break; 113918781e08Smrg case RR_Rotate_180: 114018781e08Smrg xhot = info->cursor_w - xhot - 1; 114118781e08Smrg yhot = info->cursor_h - yhot - 1; 114218781e08Smrg break; 114318781e08Smrg case RR_Rotate_270: 114418781e08Smrg t = xhot; 114518781e08Smrg xhot = info->cursor_h - yhot - 1; 114618781e08Smrg yhot = t; 114718781e08Smrg } 114818781e08Smrg } 11497314432eSmrg 115018781e08Smrg ret = 115118781e08Smrg drmModeSetCursor2(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 115218781e08Smrg handle, info->cursor_w, info->cursor_h, 115318781e08Smrg xhot, yhot); 115418781e08Smrg if (ret == -EINVAL) 115518781e08Smrg use_set_cursor2 = FALSE; 115618781e08Smrg else 115718781e08Smrg return; 115818781e08Smrg } 115918781e08Smrg 116018781e08Smrg drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, handle, 116118781e08Smrg info->cursor_w, info->cursor_h); 1162de2362d3Smrg} 1163de2362d3Smrg 11643ed65abbSmrg/* Xorg expects a non-NULL return value from drmmode_crtc_shadow_allocate, and 11653ed65abbSmrg * passes that back to drmmode_crtc_scanout_create; it doesn't use it for 11663ed65abbSmrg * anything else. 11673ed65abbSmrg */ 1168de2362d3Smrgstatic void * 1169de2362d3Smrgdrmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 1170de2362d3Smrg{ 1171de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 11727821949aSmrg 11733ed65abbSmrg if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 11743ed65abbSmrg height)) 11753ed65abbSmrg return NULL; 11763ed65abbSmrg 11773ed65abbSmrg return (void*)~0UL; 1178de2362d3Smrg} 1179de2362d3Smrg 1180de2362d3Smrgstatic PixmapPtr 1181de2362d3Smrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 1182de2362d3Smrg{ 1183de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1184de2362d3Smrg 11853ed65abbSmrg if (!data) { 11863ed65abbSmrg drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 11873ed65abbSmrg height); 11883ed65abbSmrg } 11893ed65abbSmrg 11903ed65abbSmrg return drmmode_crtc->rotate.pixmap; 1191de2362d3Smrg} 1192de2362d3Smrg 1193de2362d3Smrgstatic void 11947821949aSmrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) 1195de2362d3Smrg{ 1196de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1197de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 1198de2362d3Smrg 119918781e08Smrg drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate); 12007821949aSmrg} 1201de2362d3Smrg 12027821949aSmrgstatic void 12037821949aSmrgdrmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 12047821949aSmrg uint16_t *blue, int size) 12057821949aSmrg{ 12067821949aSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 12077821949aSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 12087314432eSmrg 120918781e08Smrg drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 121018781e08Smrg size, red, green, blue); 121118781e08Smrg} 121218781e08Smrg 121318781e08Smrg#ifdef RADEON_PIXMAP_SHARING 121418781e08Smrgstatic Bool 121518781e08Smrgdrmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) 121618781e08Smrg{ 121718781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 12183ed65abbSmrg unsigned scanout_id = drmmode_crtc->scanout_id; 121918781e08Smrg ScreenPtr screen = crtc->scrn->pScreen; 122018781e08Smrg PixmapDirtyUpdatePtr dirty; 122118781e08Smrg 122218781e08Smrg xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 12233ed65abbSmrg if (dirty->slave_dst != drmmode_crtc->scanout[scanout_id].pixmap) 122418781e08Smrg continue; 122518781e08Smrg 122618781e08Smrg PixmapStopDirtyTracking(dirty->src, dirty->slave_dst); 122718781e08Smrg drmmode_crtc_scanout_free(drmmode_crtc); 122818781e08Smrg break; 122918781e08Smrg } 123018781e08Smrg 123118781e08Smrg if (!ppix) 123218781e08Smrg return TRUE; 123318781e08Smrg 123418781e08Smrg if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0], 123518781e08Smrg ppix->drawable.width, 123618781e08Smrg ppix->drawable.height)) 123718781e08Smrg return FALSE; 123818781e08Smrg 12393ed65abbSmrg if (drmmode_crtc->tear_free && 124018781e08Smrg !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 124118781e08Smrg ppix->drawable.width, 124218781e08Smrg ppix->drawable.height)) { 124318781e08Smrg drmmode_crtc_scanout_free(drmmode_crtc); 124418781e08Smrg return FALSE; 124518781e08Smrg } 124618781e08Smrg 124718781e08Smrg#ifdef HAS_DIRTYTRACKING_ROTATION 12483ed65abbSmrg PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 124918781e08Smrg 0, 0, 0, 0, RR_Rotate_0); 125018781e08Smrg#elif defined(HAS_DIRTYTRACKING2) 12513ed65abbSmrg PixmapStartDirtyTracking2(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 125218781e08Smrg 0, 0, 0, 0); 125318781e08Smrg#else 12543ed65abbSmrg PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 0, 0); 125518781e08Smrg#endif 125618781e08Smrg return TRUE; 1257de2362d3Smrg} 125818781e08Smrg#endif 1259de2362d3Smrg 126018781e08Smrgstatic xf86CrtcFuncsRec drmmode_crtc_funcs = { 1261de2362d3Smrg .dpms = drmmode_crtc_dpms, 1262de2362d3Smrg .set_mode_major = drmmode_set_mode_major, 1263de2362d3Smrg .set_cursor_colors = drmmode_set_cursor_colors, 1264de2362d3Smrg .set_cursor_position = drmmode_set_cursor_position, 1265de2362d3Smrg .show_cursor = drmmode_show_cursor, 1266de2362d3Smrg .hide_cursor = drmmode_hide_cursor, 1267de2362d3Smrg .load_cursor_argb = drmmode_load_cursor_argb, 126818781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 126918781e08Smrg .load_cursor_argb_check = drmmode_load_cursor_argb_check, 127018781e08Smrg#endif 1271de2362d3Smrg 1272de2362d3Smrg .gamma_set = drmmode_crtc_gamma_set, 1273de2362d3Smrg .shadow_create = drmmode_crtc_shadow_create, 1274de2362d3Smrg .shadow_allocate = drmmode_crtc_shadow_allocate, 1275de2362d3Smrg .shadow_destroy = drmmode_crtc_shadow_destroy, 1276de2362d3Smrg .destroy = NULL, /* XXX */ 127718781e08Smrg#ifdef RADEON_PIXMAP_SHARING 127818781e08Smrg .set_scanout_pixmap = drmmode_set_scanout_pixmap, 127918781e08Smrg#endif 1280de2362d3Smrg}; 1281de2362d3Smrg 1282de2362d3Smrgint drmmode_get_crtc_id(xf86CrtcPtr crtc) 1283de2362d3Smrg{ 1284de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1285de2362d3Smrg return drmmode_crtc->hw_id; 1286de2362d3Smrg} 1287de2362d3Smrg 1288de2362d3Smrgvoid drmmode_crtc_hw_id(xf86CrtcPtr crtc) 1289de2362d3Smrg{ 1290de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1291de2362d3Smrg ScrnInfoPtr pScrn = crtc->scrn; 1292de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1293de2362d3Smrg struct drm_radeon_info ginfo; 1294de2362d3Smrg int r; 1295de2362d3Smrg uint32_t tmp; 1296de2362d3Smrg 1297de2362d3Smrg memset(&ginfo, 0, sizeof(ginfo)); 1298de2362d3Smrg ginfo.request = 0x4; 1299de2362d3Smrg tmp = drmmode_crtc->mode_crtc->crtc_id; 1300de2362d3Smrg ginfo.value = (uintptr_t)&tmp; 130118781e08Smrg r = drmCommandWriteRead(info->dri2.drm_fd, DRM_RADEON_INFO, &ginfo, sizeof(ginfo)); 1302de2362d3Smrg if (r) { 1303de2362d3Smrg drmmode_crtc->hw_id = -1; 1304de2362d3Smrg return; 1305de2362d3Smrg } 1306de2362d3Smrg drmmode_crtc->hw_id = tmp; 1307de2362d3Smrg} 1308de2362d3Smrg 130918781e08Smrgstatic unsigned int 131018781e08Smrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num) 1311de2362d3Smrg{ 1312de2362d3Smrg xf86CrtcPtr crtc; 1313de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc; 131418781e08Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 1315de2362d3Smrg 1316de2362d3Smrg crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs); 1317de2362d3Smrg if (crtc == NULL) 131818781e08Smrg return 0; 1319de2362d3Smrg 1320de2362d3Smrg drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); 132118781e08Smrg drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, mode_res->crtcs[num]); 1322de2362d3Smrg drmmode_crtc->drmmode = drmmode; 132318781e08Smrg drmmode_crtc->dpms_mode = DPMSModeOff; 132418781e08Smrg drmmode_crtc->pending_dpms_mode = DPMSModeOff; 1325de2362d3Smrg crtc->driver_private = drmmode_crtc; 1326de2362d3Smrg drmmode_crtc_hw_id(crtc); 1327de2362d3Smrg 132818781e08Smrg /* Mark num'th crtc as in use on this device. */ 132918781e08Smrg pRADEONEnt->assigned_crtcs |= (1 << num); 133018781e08Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 133118781e08Smrg "Allocated crtc nr. %d to this screen.\n", num); 133218781e08Smrg 133318781e08Smrg return 1; 1334de2362d3Smrg} 1335de2362d3Smrg 1336de2362d3Smrgstatic xf86OutputStatus 1337de2362d3Smrgdrmmode_output_detect(xf86OutputPtr output) 1338de2362d3Smrg{ 1339de2362d3Smrg /* go to the hw and retrieve a new output struct */ 1340de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1341de2362d3Smrg drmmode_ptr drmmode = drmmode_output->drmmode; 1342de2362d3Smrg xf86OutputStatus status; 1343de2362d3Smrg drmModeFreeConnector(drmmode_output->mode_output); 1344de2362d3Smrg 1345de2362d3Smrg drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id); 134618781e08Smrg if (!drmmode_output->mode_output) 134718781e08Smrg return XF86OutputStatusDisconnected; 1348de2362d3Smrg 1349de2362d3Smrg switch (drmmode_output->mode_output->connection) { 1350de2362d3Smrg case DRM_MODE_CONNECTED: 1351de2362d3Smrg status = XF86OutputStatusConnected; 1352de2362d3Smrg break; 1353de2362d3Smrg case DRM_MODE_DISCONNECTED: 1354de2362d3Smrg status = XF86OutputStatusDisconnected; 1355de2362d3Smrg break; 1356de2362d3Smrg default: 1357de2362d3Smrg case DRM_MODE_UNKNOWNCONNECTION: 1358de2362d3Smrg status = XF86OutputStatusUnknown; 1359de2362d3Smrg break; 1360de2362d3Smrg } 1361de2362d3Smrg return status; 1362de2362d3Smrg} 1363de2362d3Smrg 1364de2362d3Smrgstatic Bool 1365de2362d3Smrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) 1366de2362d3Smrg{ 1367de2362d3Smrg return MODE_OK; 1368de2362d3Smrg} 1369de2362d3Smrg 1370de2362d3Smrgstatic DisplayModePtr 1371de2362d3Smrgdrmmode_output_get_modes(xf86OutputPtr output) 1372de2362d3Smrg{ 1373de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1374de2362d3Smrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 1375de2362d3Smrg drmmode_ptr drmmode = drmmode_output->drmmode; 1376de2362d3Smrg int i; 1377de2362d3Smrg DisplayModePtr Modes = NULL, Mode; 1378de2362d3Smrg drmModePropertyPtr props; 1379de2362d3Smrg xf86MonPtr mon = NULL; 1380de2362d3Smrg 138118781e08Smrg if (!koutput) 138218781e08Smrg return NULL; 138318781e08Smrg 1384de2362d3Smrg /* look for an EDID property */ 1385de2362d3Smrg for (i = 0; i < koutput->count_props; i++) { 1386de2362d3Smrg props = drmModeGetProperty(drmmode->fd, koutput->props[i]); 1387de2362d3Smrg if (props && (props->flags & DRM_MODE_PROP_BLOB)) { 1388de2362d3Smrg if (!strcmp(props->name, "EDID")) { 1389de2362d3Smrg if (drmmode_output->edid_blob) 1390de2362d3Smrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 1391de2362d3Smrg drmmode_output->edid_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]); 1392de2362d3Smrg } 13937821949aSmrg } 139418781e08Smrg if (props) 139518781e08Smrg drmModeFreeProperty(props); 1396de2362d3Smrg } 1397de2362d3Smrg 1398de2362d3Smrg if (drmmode_output->edid_blob) { 1399de2362d3Smrg mon = xf86InterpretEDID(output->scrn->scrnIndex, 1400de2362d3Smrg drmmode_output->edid_blob->data); 1401de2362d3Smrg if (mon && drmmode_output->edid_blob->length > 128) 1402de2362d3Smrg mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 1403de2362d3Smrg } 1404de2362d3Smrg xf86OutputSetEDID(output, mon); 1405de2362d3Smrg 1406de2362d3Smrg /* modes should already be available */ 1407de2362d3Smrg for (i = 0; i < koutput->count_modes; i++) { 1408de2362d3Smrg Mode = xnfalloc(sizeof(DisplayModeRec)); 1409de2362d3Smrg 1410de2362d3Smrg drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode); 1411de2362d3Smrg Modes = xf86ModesAdd(Modes, Mode); 1412de2362d3Smrg 1413de2362d3Smrg } 1414de2362d3Smrg return Modes; 1415de2362d3Smrg} 1416de2362d3Smrg 1417de2362d3Smrgstatic void 1418de2362d3Smrgdrmmode_output_destroy(xf86OutputPtr output) 1419de2362d3Smrg{ 1420de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1421de2362d3Smrg int i; 1422de2362d3Smrg 1423de2362d3Smrg if (drmmode_output->edid_blob) 1424de2362d3Smrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 1425de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 1426de2362d3Smrg drmModeFreeProperty(drmmode_output->props[i].mode_prop); 1427de2362d3Smrg free(drmmode_output->props[i].atoms); 1428de2362d3Smrg } 1429de2362d3Smrg for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) { 1430de2362d3Smrg drmModeFreeEncoder(drmmode_output->mode_encoders[i]); 1431de2362d3Smrg } 143218781e08Smrg free(drmmode_output->mode_encoders); 1433de2362d3Smrg free(drmmode_output->props); 1434de2362d3Smrg drmModeFreeConnector(drmmode_output->mode_output); 1435de2362d3Smrg free(drmmode_output); 1436de2362d3Smrg output->driver_private = NULL; 1437de2362d3Smrg} 1438de2362d3Smrg 1439de2362d3Smrgstatic void 1440de2362d3Smrgdrmmode_output_dpms(xf86OutputPtr output, int mode) 1441de2362d3Smrg{ 1442de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 144318781e08Smrg xf86CrtcPtr crtc = output->crtc; 1444de2362d3Smrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 1445de2362d3Smrg drmmode_ptr drmmode = drmmode_output->drmmode; 1446de2362d3Smrg 144718781e08Smrg if (!koutput) 144818781e08Smrg return; 144918781e08Smrg 145018781e08Smrg if (mode != DPMSModeOn && crtc) { 145118781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 145218781e08Smrg 145318781e08Smrg drmmode_do_crtc_dpms(crtc, mode); 145418781e08Smrg 145518781e08Smrg /* Wait for any pending flip to finish */ 145618781e08Smrg if (drmmode_crtc->flip_pending) 145718781e08Smrg return; 145818781e08Smrg } 145918781e08Smrg 1460de2362d3Smrg drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id, 1461de2362d3Smrg drmmode_output->dpms_enum_id, mode); 146218781e08Smrg 146318781e08Smrg if (mode == DPMSModeOn && crtc) { 146418781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 146518781e08Smrg 146618781e08Smrg if (drmmode_crtc->need_modeset) 146718781e08Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x, 146818781e08Smrg crtc->y); 146918781e08Smrg else 147018781e08Smrg drmmode_do_crtc_dpms(crtc, mode); 147118781e08Smrg } 1472de2362d3Smrg} 1473de2362d3Smrg 1474de2362d3Smrg 1475de2362d3Smrgstatic Bool 1476de2362d3Smrgdrmmode_property_ignore(drmModePropertyPtr prop) 1477de2362d3Smrg{ 1478de2362d3Smrg if (!prop) 1479de2362d3Smrg return TRUE; 1480de2362d3Smrg /* ignore blob prop */ 1481de2362d3Smrg if (prop->flags & DRM_MODE_PROP_BLOB) 1482de2362d3Smrg return TRUE; 1483de2362d3Smrg /* ignore standard property */ 1484de2362d3Smrg if (!strcmp(prop->name, "EDID") || 1485de2362d3Smrg !strcmp(prop->name, "DPMS")) 1486de2362d3Smrg return TRUE; 1487de2362d3Smrg 1488de2362d3Smrg return FALSE; 1489de2362d3Smrg} 1490de2362d3Smrg 1491de2362d3Smrgstatic void 1492de2362d3Smrgdrmmode_output_create_resources(xf86OutputPtr output) 1493de2362d3Smrg{ 14943ed65abbSmrg RADEONInfoPtr info = RADEONPTR(output->scrn); 1495de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1496de2362d3Smrg drmModeConnectorPtr mode_output = drmmode_output->mode_output; 1497de2362d3Smrg drmmode_ptr drmmode = drmmode_output->drmmode; 14983ed65abbSmrg drmModePropertyPtr drmmode_prop, tearfree_prop; 1499de2362d3Smrg int i, j, err; 1500de2362d3Smrg 15013ed65abbSmrg drmmode_output->props = calloc(mode_output->count_props + 1, sizeof(drmmode_prop_rec)); 1502de2362d3Smrg if (!drmmode_output->props) 1503de2362d3Smrg return; 1504de2362d3Smrg 1505de2362d3Smrg drmmode_output->num_props = 0; 1506de2362d3Smrg for (i = 0, j = 0; i < mode_output->count_props; i++) { 1507de2362d3Smrg drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]); 1508de2362d3Smrg if (drmmode_property_ignore(drmmode_prop)) { 1509de2362d3Smrg drmModeFreeProperty(drmmode_prop); 1510de2362d3Smrg continue; 1511de2362d3Smrg } 1512de2362d3Smrg drmmode_output->props[j].mode_prop = drmmode_prop; 1513de2362d3Smrg drmmode_output->props[j].value = mode_output->prop_values[i]; 1514de2362d3Smrg drmmode_output->num_props++; 1515de2362d3Smrg j++; 1516de2362d3Smrg } 1517de2362d3Smrg 15183ed65abbSmrg /* Userspace-only property for TearFree */ 15193ed65abbSmrg tearfree_prop = calloc(1, sizeof(*tearfree_prop)); 15203ed65abbSmrg tearfree_prop->flags = DRM_MODE_PROP_ENUM; 15213ed65abbSmrg strncpy(tearfree_prop->name, "TearFree", 8); 15223ed65abbSmrg tearfree_prop->count_enums = 3; 15233ed65abbSmrg tearfree_prop->enums = calloc(tearfree_prop->count_enums, 15243ed65abbSmrg sizeof(*tearfree_prop->enums)); 15253ed65abbSmrg strncpy(tearfree_prop->enums[0].name, "off", 3); 15263ed65abbSmrg strncpy(tearfree_prop->enums[1].name, "on", 2); 15273ed65abbSmrg tearfree_prop->enums[1].value = 1; 15283ed65abbSmrg strncpy(tearfree_prop->enums[2].name, "auto", 4); 15293ed65abbSmrg tearfree_prop->enums[2].value = 2; 15303ed65abbSmrg drmmode_output->props[j].mode_prop = tearfree_prop; 15313ed65abbSmrg drmmode_output->props[j].value = info->tear_free; 15323ed65abbSmrg drmmode_output->tear_free = info->tear_free; 15333ed65abbSmrg drmmode_output->num_props++; 15343ed65abbSmrg 1535de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 1536de2362d3Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 1537de2362d3Smrg drmmode_prop = p->mode_prop; 1538de2362d3Smrg 1539de2362d3Smrg if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 1540de2362d3Smrg INT32 range[2]; 1541de2362d3Smrg INT32 value = p->value; 1542de2362d3Smrg 1543de2362d3Smrg p->num_atoms = 1; 1544de2362d3Smrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 1545de2362d3Smrg if (!p->atoms) 1546de2362d3Smrg continue; 1547de2362d3Smrg p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 1548de2362d3Smrg range[0] = drmmode_prop->values[0]; 1549de2362d3Smrg range[1] = drmmode_prop->values[1]; 1550de2362d3Smrg err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 1551de2362d3Smrg FALSE, TRUE, 1552de2362d3Smrg drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 1553de2362d3Smrg 2, range); 1554de2362d3Smrg if (err != 0) { 1555de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1556de2362d3Smrg "RRConfigureOutputProperty error, %d\n", err); 1557de2362d3Smrg } 1558de2362d3Smrg err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 1559de2362d3Smrg XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, TRUE); 1560de2362d3Smrg if (err != 0) { 1561de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1562de2362d3Smrg "RRChangeOutputProperty error, %d\n", err); 1563de2362d3Smrg } 1564de2362d3Smrg } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 1565de2362d3Smrg p->num_atoms = drmmode_prop->count_enums + 1; 1566de2362d3Smrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 1567de2362d3Smrg if (!p->atoms) 1568de2362d3Smrg continue; 1569de2362d3Smrg p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 1570de2362d3Smrg for (j = 1; j <= drmmode_prop->count_enums; j++) { 1571de2362d3Smrg struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; 1572de2362d3Smrg p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); 1573de2362d3Smrg } 1574de2362d3Smrg err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 1575de2362d3Smrg FALSE, FALSE, 1576de2362d3Smrg drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 1577de2362d3Smrg p->num_atoms - 1, (INT32 *)&p->atoms[1]); 1578de2362d3Smrg if (err != 0) { 1579de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1580de2362d3Smrg "RRConfigureOutputProperty error, %d\n", err); 1581de2362d3Smrg } 1582de2362d3Smrg for (j = 0; j < drmmode_prop->count_enums; j++) 1583de2362d3Smrg if (drmmode_prop->enums[j].value == p->value) 1584de2362d3Smrg break; 1585de2362d3Smrg /* there's always a matching value */ 1586de2362d3Smrg err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 1587de2362d3Smrg XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE); 1588de2362d3Smrg if (err != 0) { 1589de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1590de2362d3Smrg "RRChangeOutputProperty error, %d\n", err); 1591de2362d3Smrg } 1592de2362d3Smrg } 1593de2362d3Smrg } 1594de2362d3Smrg} 1595de2362d3Smrg 1596de2362d3Smrgstatic Bool 1597de2362d3Smrgdrmmode_output_set_property(xf86OutputPtr output, Atom property, 1598de2362d3Smrg RRPropertyValuePtr value) 1599de2362d3Smrg{ 1600de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1601de2362d3Smrg drmmode_ptr drmmode = drmmode_output->drmmode; 1602de2362d3Smrg int i; 1603de2362d3Smrg 1604de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 1605de2362d3Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 1606de2362d3Smrg 1607de2362d3Smrg if (p->atoms[0] != property) 1608de2362d3Smrg continue; 1609de2362d3Smrg 1610de2362d3Smrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 1611de2362d3Smrg uint32_t val; 1612de2362d3Smrg 1613de2362d3Smrg if (value->type != XA_INTEGER || value->format != 32 || 1614de2362d3Smrg value->size != 1) 1615de2362d3Smrg return FALSE; 1616de2362d3Smrg val = *(uint32_t *)value->data; 1617de2362d3Smrg 1618de2362d3Smrg drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, 1619de2362d3Smrg p->mode_prop->prop_id, (uint64_t)val); 1620de2362d3Smrg return TRUE; 1621de2362d3Smrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 1622de2362d3Smrg Atom atom; 1623de2362d3Smrg const char *name; 1624de2362d3Smrg int j; 1625de2362d3Smrg 1626de2362d3Smrg if (value->type != XA_ATOM || value->format != 32 || value->size != 1) 1627de2362d3Smrg return FALSE; 1628de2362d3Smrg memcpy(&atom, value->data, 4); 1629de2362d3Smrg name = NameForAtom(atom); 1630de2362d3Smrg 1631de2362d3Smrg /* search for matching name string, then set its value down */ 1632de2362d3Smrg for (j = 0; j < p->mode_prop->count_enums; j++) { 1633de2362d3Smrg if (!strcmp(p->mode_prop->enums[j].name, name)) { 16343ed65abbSmrg if (i == (drmmode_output->num_props - 1)) { 16353ed65abbSmrg if (drmmode_output->tear_free != j) { 16363ed65abbSmrg xf86CrtcPtr crtc = output->crtc; 16373ed65abbSmrg 16383ed65abbSmrg drmmode_output->tear_free = j; 16393ed65abbSmrg if (crtc) { 16403ed65abbSmrg drmmode_set_mode_major(crtc, &crtc->mode, 16413ed65abbSmrg crtc->rotation, 16423ed65abbSmrg crtc->x, crtc->y); 16433ed65abbSmrg } 16443ed65abbSmrg } 16453ed65abbSmrg } else { 16463ed65abbSmrg drmModeConnectorSetProperty(drmmode->fd, 16473ed65abbSmrg drmmode_output->output_id, 16483ed65abbSmrg p->mode_prop->prop_id, 16493ed65abbSmrg p->mode_prop->enums[j].value); 16503ed65abbSmrg } 16513ed65abbSmrg 1652de2362d3Smrg return TRUE; 1653de2362d3Smrg } 1654de2362d3Smrg } 1655de2362d3Smrg } 1656de2362d3Smrg } 1657de2362d3Smrg 1658de2362d3Smrg return TRUE; 1659de2362d3Smrg} 1660de2362d3Smrg 1661de2362d3Smrgstatic Bool 1662de2362d3Smrgdrmmode_output_get_property(xf86OutputPtr output, Atom property) 1663de2362d3Smrg{ 1664de2362d3Smrg return TRUE; 1665de2362d3Smrg} 1666de2362d3Smrg 1667de2362d3Smrgstatic const xf86OutputFuncsRec drmmode_output_funcs = { 1668de2362d3Smrg .dpms = drmmode_output_dpms, 1669de2362d3Smrg .create_resources = drmmode_output_create_resources, 1670de2362d3Smrg .set_property = drmmode_output_set_property, 1671de2362d3Smrg .get_property = drmmode_output_get_property, 1672de2362d3Smrg#if 0 1673de2362d3Smrg 1674de2362d3Smrg .save = drmmode_crt_save, 1675de2362d3Smrg .restore = drmmode_crt_restore, 1676de2362d3Smrg .mode_fixup = drmmode_crt_mode_fixup, 1677de2362d3Smrg .prepare = drmmode_output_prepare, 1678de2362d3Smrg .mode_set = drmmode_crt_mode_set, 1679de2362d3Smrg .commit = drmmode_output_commit, 1680de2362d3Smrg#endif 1681de2362d3Smrg .detect = drmmode_output_detect, 1682de2362d3Smrg .mode_valid = drmmode_output_mode_valid, 1683de2362d3Smrg 1684de2362d3Smrg .get_modes = drmmode_output_get_modes, 1685de2362d3Smrg .destroy = drmmode_output_destroy 1686de2362d3Smrg}; 1687de2362d3Smrg 1688de2362d3Smrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown, 1689de2362d3Smrg SubPixelHorizontalRGB, 1690de2362d3Smrg SubPixelHorizontalBGR, 1691de2362d3Smrg SubPixelVerticalRGB, 1692de2362d3Smrg SubPixelVerticalBGR, 1693de2362d3Smrg SubPixelNone }; 1694de2362d3Smrg 1695de2362d3Smrgconst char *output_names[] = { "None", 1696de2362d3Smrg "VGA", 1697de2362d3Smrg "DVI", 1698de2362d3Smrg "DVI", 1699de2362d3Smrg "DVI", 1700de2362d3Smrg "Composite", 1701de2362d3Smrg "S-video", 1702de2362d3Smrg "LVDS", 1703de2362d3Smrg "CTV", 1704de2362d3Smrg "DIN", 1705de2362d3Smrg "DisplayPort", 1706de2362d3Smrg "HDMI", 1707de2362d3Smrg "HDMI", 1708de2362d3Smrg "TV", 1709de2362d3Smrg "eDP" 1710de2362d3Smrg}; 1711de2362d3Smrg 171218781e08Smrg#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0])) 171318781e08Smrg 171418781e08Smrgstatic xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id) 171518781e08Smrg{ 171618781e08Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 171718781e08Smrg int i; 171818781e08Smrg for (i = 0; i < xf86_config->num_output; i++) { 171918781e08Smrg xf86OutputPtr output = xf86_config->output[i]; 172018781e08Smrg drmmode_output_private_ptr drmmode_output; 172118781e08Smrg 172218781e08Smrg drmmode_output = output->driver_private; 172318781e08Smrg if (drmmode_output->output_id == id) 172418781e08Smrg return output; 172518781e08Smrg } 172618781e08Smrg return NULL; 172718781e08Smrg} 172818781e08Smrg 172918781e08Smrgstatic int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path) 173018781e08Smrg{ 173118781e08Smrg char *conn; 173218781e08Smrg char conn_id[5]; 173318781e08Smrg int id, len; 173418781e08Smrg char *blob_data; 173518781e08Smrg 173618781e08Smrg if (!path_blob) 173718781e08Smrg return -1; 173818781e08Smrg 173918781e08Smrg blob_data = path_blob->data; 174018781e08Smrg /* we only handle MST paths for now */ 174118781e08Smrg if (strncmp(blob_data, "mst:", 4)) 174218781e08Smrg return -1; 174318781e08Smrg 174418781e08Smrg conn = strchr(blob_data + 4, '-'); 174518781e08Smrg if (!conn) 174618781e08Smrg return -1; 174718781e08Smrg len = conn - (blob_data + 4); 174818781e08Smrg if (len + 1 > 5) 174918781e08Smrg return -1; 175018781e08Smrg memcpy(conn_id, blob_data + 4, len); 175118781e08Smrg conn_id[len] = '\0'; 175218781e08Smrg id = strtoul(conn_id, NULL, 10); 175318781e08Smrg 175418781e08Smrg *conn_base_id = id; 175518781e08Smrg 175618781e08Smrg *path = conn + 1; 175718781e08Smrg return 0; 175818781e08Smrg} 175918781e08Smrg 1760de2362d3Smrgstatic void 176118781e08Smrgdrmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name, 176218781e08Smrg drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi) 176318781e08Smrg{ 176418781e08Smrg xf86OutputPtr output; 176518781e08Smrg int conn_id; 176618781e08Smrg char *extra_path; 176718781e08Smrg 176818781e08Smrg output = NULL; 176918781e08Smrg if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0) 177018781e08Smrg output = find_output(pScrn, conn_id); 177118781e08Smrg if (output) { 177218781e08Smrg snprintf(name, 32, "%s-%s", output->name, extra_path); 177318781e08Smrg } else { 177418781e08Smrg if (koutput->connector_type >= NUM_OUTPUT_NAMES) 177518781e08Smrg snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, 177618781e08Smrg koutput->connector_type_id - 1); 177718781e08Smrg#ifdef RADEON_PIXMAP_SHARING 177818781e08Smrg else if (pScrn->is_gpu) 177918781e08Smrg snprintf(name, 32, "%s-%d-%d", 178018781e08Smrg output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, 178118781e08Smrg koutput->connector_type_id - 1); 178218781e08Smrg#endif 178318781e08Smrg else { 178418781e08Smrg /* need to do smart conversion here for compat with non-kms ATI driver */ 178518781e08Smrg if (koutput->connector_type_id == 1) { 178618781e08Smrg switch(koutput->connector_type) { 178718781e08Smrg case DRM_MODE_CONNECTOR_DVII: 178818781e08Smrg case DRM_MODE_CONNECTOR_DVID: 178918781e08Smrg case DRM_MODE_CONNECTOR_DVIA: 179018781e08Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi); 179118781e08Smrg (*num_dvi)++; 179218781e08Smrg break; 179318781e08Smrg case DRM_MODE_CONNECTOR_HDMIA: 179418781e08Smrg case DRM_MODE_CONNECTOR_HDMIB: 179518781e08Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi); 179618781e08Smrg (*num_hdmi)++; 179718781e08Smrg break; 179818781e08Smrg case DRM_MODE_CONNECTOR_VGA: 179918781e08Smrg case DRM_MODE_CONNECTOR_DisplayPort: 180018781e08Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], 180118781e08Smrg koutput->connector_type_id - 1); 180218781e08Smrg break; 180318781e08Smrg default: 180418781e08Smrg snprintf(name, 32, "%s", output_names[koutput->connector_type]); 180518781e08Smrg break; 180618781e08Smrg } 180718781e08Smrg } else { 180818781e08Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], 180918781e08Smrg koutput->connector_type_id - 1); 181018781e08Smrg } 181118781e08Smrg } 181218781e08Smrg } 181318781e08Smrg} 181418781e08Smrg 181518781e08Smrgstatic unsigned int 181618781e08Smrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic) 18170d16fef4Smrg{ 181818781e08Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1819de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1820de2362d3Smrg xf86OutputPtr output; 1821de2362d3Smrg drmModeConnectorPtr koutput; 1822de2362d3Smrg drmModeEncoderPtr *kencoders = NULL; 1823de2362d3Smrg drmmode_output_private_ptr drmmode_output; 1824de2362d3Smrg drmModePropertyPtr props; 182518781e08Smrg drmModePropertyBlobPtr path_blob = NULL; 1826de2362d3Smrg char name[32]; 1827de2362d3Smrg int i; 1828de2362d3Smrg const char *s; 1829de2362d3Smrg 183018781e08Smrg koutput = drmModeGetConnector(drmmode->fd, mode_res->connectors[num]); 1831de2362d3Smrg if (!koutput) 183218781e08Smrg return 0; 183318781e08Smrg 183418781e08Smrg for (i = 0; i < koutput->count_props; i++) { 183518781e08Smrg props = drmModeGetProperty(drmmode->fd, koutput->props[i]); 183618781e08Smrg if (props && (props->flags & DRM_MODE_PROP_BLOB)) { 183718781e08Smrg if (!strcmp(props->name, "PATH")) { 183818781e08Smrg path_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]); 183918781e08Smrg drmModeFreeProperty(props); 184018781e08Smrg break; 184118781e08Smrg } 184218781e08Smrg drmModeFreeProperty(props); 184318781e08Smrg } 184418781e08Smrg } 1845de2362d3Smrg 1846de2362d3Smrg kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); 1847de2362d3Smrg if (!kencoders) { 1848de2362d3Smrg goto out_free_encoders; 1849de2362d3Smrg } 1850de2362d3Smrg 1851de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) { 1852de2362d3Smrg kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]); 1853de2362d3Smrg if (!kencoders[i]) { 1854de2362d3Smrg goto out_free_encoders; 1855de2362d3Smrg } 1856de2362d3Smrg } 1857de2362d3Smrg 185818781e08Smrg drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi); 185918781e08Smrg if (path_blob) 186018781e08Smrg drmModeFreePropertyBlob(path_blob); 186118781e08Smrg 186218781e08Smrg if (path_blob && dynamic) { 186318781e08Smrg /* See if we have an output with this name already 186418781e08Smrg * and hook stuff up. 186518781e08Smrg */ 186618781e08Smrg for (i = 0; i < xf86_config->num_output; i++) { 186718781e08Smrg output = xf86_config->output[i]; 186818781e08Smrg 186918781e08Smrg if (strncmp(output->name, name, 32)) 187018781e08Smrg continue; 187118781e08Smrg 187218781e08Smrg drmmode_output = output->driver_private; 187318781e08Smrg drmmode_output->output_id = mode_res->connectors[num]; 187418781e08Smrg drmmode_output->mode_output = koutput; 187518781e08Smrg for (i = 0; i < koutput->count_encoders; i++) 187618781e08Smrg drmModeFreeEncoder(kencoders[i]); 187718781e08Smrg free(kencoders); 187818781e08Smrg return 0; 187918781e08Smrg } 1880de2362d3Smrg } 1881de2362d3Smrg 1882de2362d3Smrg if (xf86IsEntityShared(pScrn->entityList[0])) { 1883de2362d3Smrg if ((s = xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) { 1884de2362d3Smrg if (!RADEONZaphodStringMatches(pScrn, s, name)) 1885de2362d3Smrg goto out_free_encoders; 1886de2362d3Smrg } else { 188718781e08Smrg if (!info->IsSecondary && (num != 0)) 1888de2362d3Smrg goto out_free_encoders; 1889de2362d3Smrg else if (info->IsSecondary && (num != 1)) 1890de2362d3Smrg goto out_free_encoders; 1891de2362d3Smrg } 1892de2362d3Smrg } 1893de2362d3Smrg 1894de2362d3Smrg output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name); 1895de2362d3Smrg if (!output) { 1896de2362d3Smrg goto out_free_encoders; 1897de2362d3Smrg } 1898de2362d3Smrg 1899de2362d3Smrg drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); 1900de2362d3Smrg if (!drmmode_output) { 1901de2362d3Smrg xf86OutputDestroy(output); 1902de2362d3Smrg goto out_free_encoders; 1903de2362d3Smrg } 1904de2362d3Smrg 190518781e08Smrg drmmode_output->output_id = mode_res->connectors[num]; 1906de2362d3Smrg drmmode_output->mode_output = koutput; 1907de2362d3Smrg drmmode_output->mode_encoders = kencoders; 1908de2362d3Smrg drmmode_output->drmmode = drmmode; 1909de2362d3Smrg output->mm_width = koutput->mmWidth; 1910de2362d3Smrg output->mm_height = koutput->mmHeight; 1911de2362d3Smrg 1912de2362d3Smrg output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 1913de2362d3Smrg output->interlaceAllowed = TRUE; 1914de2362d3Smrg output->doubleScanAllowed = TRUE; 1915de2362d3Smrg output->driver_private = drmmode_output; 1916de2362d3Smrg 1917de2362d3Smrg output->possible_crtcs = 0xffffffff; 1918de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) { 1919de2362d3Smrg output->possible_crtcs &= kencoders[i]->possible_crtcs; 1920de2362d3Smrg } 1921de2362d3Smrg /* work out the possible clones later */ 1922de2362d3Smrg output->possible_clones = 0; 1923de2362d3Smrg 1924de2362d3Smrg for (i = 0; i < koutput->count_props; i++) { 1925de2362d3Smrg props = drmModeGetProperty(drmmode->fd, koutput->props[i]); 1926de2362d3Smrg if (props && (props->flags & DRM_MODE_PROP_ENUM)) { 1927de2362d3Smrg if (!strcmp(props->name, "DPMS")) { 1928de2362d3Smrg drmmode_output->dpms_enum_id = koutput->props[i]; 1929de2362d3Smrg drmModeFreeProperty(props); 1930de2362d3Smrg break; 1931de2362d3Smrg } 1932de2362d3Smrg drmModeFreeProperty(props); 1933de2362d3Smrg } 1934de2362d3Smrg } 1935de2362d3Smrg 193618781e08Smrg if (dynamic) { 193718781e08Smrg output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output); 193818781e08Smrg drmmode_output_create_resources(output); 193918781e08Smrg } 194018781e08Smrg 194118781e08Smrg return 1; 1942de2362d3Smrgout_free_encoders: 1943de2362d3Smrg if (kencoders){ 1944de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) 1945de2362d3Smrg drmModeFreeEncoder(kencoders[i]); 1946de2362d3Smrg free(kencoders); 1947de2362d3Smrg } 1948de2362d3Smrg drmModeFreeConnector(koutput); 194918781e08Smrg return 0; 1950de2362d3Smrg} 1951de2362d3Smrg 1952de2362d3Smrguint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output) 1953de2362d3Smrg{ 1954de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private, clone_drmout; 1955de2362d3Smrg int i; 1956de2362d3Smrg xf86OutputPtr clone_output; 1957de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1958de2362d3Smrg int index_mask = 0; 1959de2362d3Smrg 1960de2362d3Smrg if (drmmode_output->enc_clone_mask == 0) 1961de2362d3Smrg return index_mask; 1962de2362d3Smrg 1963de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 1964de2362d3Smrg clone_output = xf86_config->output[i]; 1965de2362d3Smrg clone_drmout = clone_output->driver_private; 1966de2362d3Smrg if (output == clone_output) 1967de2362d3Smrg continue; 1968de2362d3Smrg 1969de2362d3Smrg if (clone_drmout->enc_mask == 0) 1970de2362d3Smrg continue; 1971de2362d3Smrg if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask) 1972de2362d3Smrg index_mask |= (1 << i); 1973de2362d3Smrg } 1974de2362d3Smrg return index_mask; 1975de2362d3Smrg} 1976de2362d3Smrg 1977de2362d3Smrg 1978de2362d3Smrgstatic void 197918781e08Smrgdrmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res) 1980de2362d3Smrg{ 1981de2362d3Smrg int i, j; 1982de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1983de2362d3Smrg 1984de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 1985de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 1986de2362d3Smrg drmmode_output_private_ptr drmmode_output; 1987de2362d3Smrg 1988de2362d3Smrg drmmode_output = output->driver_private; 1989de2362d3Smrg drmmode_output->enc_clone_mask = 0xff; 1990de2362d3Smrg /* and all the possible encoder clones for this output together */ 1991de2362d3Smrg for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) 1992de2362d3Smrg { 1993de2362d3Smrg int k; 199418781e08Smrg for (k = 0; k < mode_res->count_encoders; k++) { 199518781e08Smrg if (mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id) 1996de2362d3Smrg drmmode_output->enc_mask |= (1 << k); 1997de2362d3Smrg } 1998de2362d3Smrg 1999de2362d3Smrg drmmode_output->enc_clone_mask &= drmmode_output->mode_encoders[j]->possible_clones; 2000de2362d3Smrg } 2001de2362d3Smrg } 2002de2362d3Smrg 2003de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 2004de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 2005de2362d3Smrg output->possible_clones = find_clones(scrn, output); 2006de2362d3Smrg } 2007de2362d3Smrg} 2008de2362d3Smrg 2009de2362d3Smrg/* returns height alignment in pixels */ 2010de2362d3Smrgint drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling) 2011de2362d3Smrg{ 2012de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 2013de2362d3Smrg int height_align = 1; 2014de2362d3Smrg 2015de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 2016de2362d3Smrg if (tiling & RADEON_TILING_MACRO) 2017de2362d3Smrg height_align = info->num_channels * 8; 2018de2362d3Smrg else if (tiling & RADEON_TILING_MICRO) 2019de2362d3Smrg height_align = 8; 2020de2362d3Smrg else 2021de2362d3Smrg height_align = 8; 2022de2362d3Smrg } else { 202318781e08Smrg if (tiling & RADEON_TILING_MICRO_SQUARE) 202418781e08Smrg height_align = 32; 202518781e08Smrg else if (tiling) 2026de2362d3Smrg height_align = 16; 2027de2362d3Smrg else 2028de2362d3Smrg height_align = 1; 2029de2362d3Smrg } 2030de2362d3Smrg return height_align; 2031de2362d3Smrg} 2032de2362d3Smrg 2033de2362d3Smrg/* returns pitch alignment in pixels */ 2034de2362d3Smrgint drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling) 2035de2362d3Smrg{ 2036de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 2037de2362d3Smrg int pitch_align = 1; 2038de2362d3Smrg 2039de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 2040de2362d3Smrg if (tiling & RADEON_TILING_MACRO) { 2041de2362d3Smrg /* general surface requirements */ 2042de2362d3Smrg pitch_align = MAX(info->num_banks, 2043de2362d3Smrg (((info->group_bytes / 8) / bpe) * info->num_banks)) * 8; 2044de2362d3Smrg /* further restrictions for scanout */ 2045de2362d3Smrg pitch_align = MAX(info->num_banks * 8, pitch_align); 2046de2362d3Smrg } else if (tiling & RADEON_TILING_MICRO) { 2047de2362d3Smrg /* general surface requirements */ 2048de2362d3Smrg pitch_align = MAX(8, (info->group_bytes / (8 * bpe))); 2049de2362d3Smrg /* further restrictions for scanout */ 2050de2362d3Smrg pitch_align = MAX(info->group_bytes / bpe, pitch_align); 2051de2362d3Smrg } else { 2052de2362d3Smrg if (info->have_tiling_info) 2053de2362d3Smrg /* linear aligned requirements */ 2054de2362d3Smrg pitch_align = MAX(64, info->group_bytes / bpe); 2055de2362d3Smrg else 2056de2362d3Smrg /* default to 512 elements if we don't know the real 2057de2362d3Smrg * group size otherwise the kernel may reject the CS 2058de2362d3Smrg * if the group sizes don't match as the pitch won't 2059de2362d3Smrg * be aligned properly. 2060de2362d3Smrg */ 2061de2362d3Smrg pitch_align = 512; 2062de2362d3Smrg } 2063de2362d3Smrg } else { 2064de2362d3Smrg /* general surface requirements */ 2065de2362d3Smrg if (tiling) 2066de2362d3Smrg pitch_align = 256 / bpe; 2067de2362d3Smrg else 2068de2362d3Smrg pitch_align = 64; 2069de2362d3Smrg } 2070de2362d3Smrg return pitch_align; 2071de2362d3Smrg} 2072de2362d3Smrg 2073de2362d3Smrg/* returns base alignment in bytes */ 2074de2362d3Smrgint drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling) 2075de2362d3Smrg{ 2076de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 2077de2362d3Smrg int pixel_align = drmmode_get_pitch_align(scrn, bpe, tiling); 2078de2362d3Smrg int height_align = drmmode_get_height_align(scrn, tiling); 2079de2362d3Smrg int base_align = RADEON_GPU_PAGE_SIZE; 2080de2362d3Smrg 2081de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 2082de2362d3Smrg if (tiling & RADEON_TILING_MACRO) 2083de2362d3Smrg base_align = MAX(info->num_banks * info->num_channels * 8 * 8 * bpe, 2084de2362d3Smrg pixel_align * bpe * height_align); 2085de2362d3Smrg else { 2086de2362d3Smrg if (info->have_tiling_info) 2087de2362d3Smrg base_align = info->group_bytes; 2088de2362d3Smrg else 2089de2362d3Smrg /* default to 512 if we don't know the real 2090de2362d3Smrg * group size otherwise the kernel may reject the CS 2091de2362d3Smrg * if the group sizes don't match as the base won't 2092de2362d3Smrg * be aligned properly. 2093de2362d3Smrg */ 2094de2362d3Smrg base_align = 512; 2095de2362d3Smrg } 2096de2362d3Smrg } 2097de2362d3Smrg return base_align; 2098de2362d3Smrg} 2099de2362d3Smrg 2100de2362d3Smrgstatic Bool 2101de2362d3Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) 2102de2362d3Smrg{ 2103de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2104de2362d3Smrg drmmode_crtc_private_ptr 2105de2362d3Smrg drmmode_crtc = xf86_config->crtc[0]->driver_private; 2106de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 2107de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 2108de2362d3Smrg struct radeon_bo *old_front = NULL; 2109de2362d3Smrg ScreenPtr screen = xf86ScrnToScreen(scrn); 2110de2362d3Smrg uint32_t old_fb_id; 2111de2362d3Smrg int i, pitch, old_width, old_height, old_pitch; 211218781e08Smrg int aligned_height; 211318781e08Smrg uint32_t screen_size; 211418781e08Smrg int cpp = info->pixel_bytes; 2115de2362d3Smrg struct radeon_bo *front_bo; 2116de2362d3Smrg struct radeon_surface surface; 2117de2362d3Smrg struct radeon_surface *psurface; 2118de2362d3Smrg uint32_t tiling_flags = 0, base_align; 2119de2362d3Smrg PixmapPtr ppix = screen->GetScreenPixmap(screen); 2120de2362d3Smrg void *fb_shadow; 212118781e08Smrg xRectangle rect; 212218781e08Smrg Bool force; 212318781e08Smrg GCPtr gc; 2124de2362d3Smrg 2125de2362d3Smrg if (scrn->virtualX == width && scrn->virtualY == height) 2126de2362d3Smrg return TRUE; 2127de2362d3Smrg 2128de2362d3Smrg front_bo = info->front_bo; 2129de2362d3Smrg radeon_cs_flush_indirect(scrn); 2130de2362d3Smrg 2131de2362d3Smrg if (front_bo) 2132de2362d3Smrg radeon_bo_wait(front_bo); 2133de2362d3Smrg 213418781e08Smrg if (info->allowColorTiling && !info->shadow_primary) { 2135de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 2136de2362d3Smrg if (info->allowColorTiling2D) { 2137de2362d3Smrg tiling_flags |= RADEON_TILING_MACRO; 2138de2362d3Smrg } else { 2139de2362d3Smrg tiling_flags |= RADEON_TILING_MICRO; 2140de2362d3Smrg } 2141de2362d3Smrg } else 2142de2362d3Smrg tiling_flags |= RADEON_TILING_MACRO; 2143de2362d3Smrg } 2144de2362d3Smrg 2145de2362d3Smrg pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(scrn, cpp, tiling_flags)) * cpp; 214618781e08Smrg aligned_height = RADEON_ALIGN(height, drmmode_get_height_align(scrn, tiling_flags)); 214718781e08Smrg screen_size = RADEON_ALIGN(pitch * aligned_height, RADEON_GPU_PAGE_SIZE); 2148de2362d3Smrg base_align = 4096; 2149de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 2150de2362d3Smrg memset(&surface, 0, sizeof(struct radeon_surface)); 2151de2362d3Smrg surface.npix_x = width; 2152de2362d3Smrg surface.npix_y = height; 2153de2362d3Smrg surface.npix_z = 1; 2154de2362d3Smrg surface.blk_w = 1; 2155de2362d3Smrg surface.blk_h = 1; 2156de2362d3Smrg surface.blk_d = 1; 2157de2362d3Smrg surface.array_size = 1; 2158de2362d3Smrg surface.last_level = 0; 2159de2362d3Smrg surface.bpe = cpp; 2160de2362d3Smrg surface.nsamples = 1; 2161de2362d3Smrg surface.flags = RADEON_SURF_SCANOUT; 216218781e08Smrg /* we are requiring a recent enough libdrm version */ 216318781e08Smrg surface.flags |= RADEON_SURF_HAS_TILE_MODE_INDEX; 2164de2362d3Smrg surface.flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); 2165de2362d3Smrg surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR_ALIGNED, MODE); 2166de2362d3Smrg if (tiling_flags & RADEON_TILING_MICRO) { 2167de2362d3Smrg surface.flags = RADEON_SURF_CLR(surface.flags, MODE); 2168de2362d3Smrg surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE); 2169de2362d3Smrg } 2170de2362d3Smrg if (tiling_flags & RADEON_TILING_MACRO) { 2171de2362d3Smrg surface.flags = RADEON_SURF_CLR(surface.flags, MODE); 2172de2362d3Smrg surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE); 2173de2362d3Smrg } 2174de2362d3Smrg if (radeon_surface_best(info->surf_man, &surface)) { 2175de2362d3Smrg return FALSE; 2176de2362d3Smrg } 2177de2362d3Smrg if (radeon_surface_init(info->surf_man, &surface)) { 2178de2362d3Smrg return FALSE; 2179de2362d3Smrg } 2180de2362d3Smrg screen_size = surface.bo_size; 2181de2362d3Smrg base_align = surface.bo_alignment; 2182de2362d3Smrg pitch = surface.level[0].pitch_bytes; 2183de2362d3Smrg tiling_flags = 0; 2184de2362d3Smrg switch (surface.level[0].mode) { 2185de2362d3Smrg case RADEON_SURF_MODE_2D: 2186de2362d3Smrg tiling_flags |= RADEON_TILING_MACRO; 2187de2362d3Smrg tiling_flags |= surface.bankw << RADEON_TILING_EG_BANKW_SHIFT; 2188de2362d3Smrg tiling_flags |= surface.bankh << RADEON_TILING_EG_BANKH_SHIFT; 2189de2362d3Smrg tiling_flags |= surface.mtilea << RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT; 219018781e08Smrg if (surface.tile_split) 219118781e08Smrg tiling_flags |= eg_tile_split(surface.tile_split) 219218781e08Smrg << RADEON_TILING_EG_TILE_SPLIT_SHIFT; 2193de2362d3Smrg break; 2194de2362d3Smrg case RADEON_SURF_MODE_1D: 2195de2362d3Smrg tiling_flags |= RADEON_TILING_MICRO; 2196de2362d3Smrg break; 2197de2362d3Smrg default: 2198de2362d3Smrg break; 2199de2362d3Smrg } 2200de2362d3Smrg info->front_surface = surface; 2201de2362d3Smrg } 2202de2362d3Smrg 2203de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_INFO, 2204de2362d3Smrg "Allocate new frame buffer %dx%d stride %d\n", 2205de2362d3Smrg width, height, pitch / cpp); 2206de2362d3Smrg 2207de2362d3Smrg old_width = scrn->virtualX; 2208de2362d3Smrg old_height = scrn->virtualY; 2209de2362d3Smrg old_pitch = scrn->displayWidth; 2210de2362d3Smrg old_fb_id = drmmode->fb_id; 221118781e08Smrg drmmode->fb_id = 0; 2212de2362d3Smrg old_front = info->front_bo; 2213de2362d3Smrg 2214de2362d3Smrg scrn->virtualX = width; 2215de2362d3Smrg scrn->virtualY = height; 2216de2362d3Smrg scrn->displayWidth = pitch / cpp; 2217de2362d3Smrg 221818781e08Smrg info->front_bo = radeon_bo_open(info->bufmgr, 0, screen_size, base_align, 221918781e08Smrg info->shadow_primary ? 222018781e08Smrg RADEON_GEM_DOMAIN_GTT : 222118781e08Smrg RADEON_GEM_DOMAIN_VRAM, 222218781e08Smrg tiling_flags ? RADEON_GEM_NO_CPU_ACCESS : 0); 2223de2362d3Smrg if (!info->front_bo) 2224de2362d3Smrg goto fail; 2225de2362d3Smrg 2226de2362d3Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN 2227de2362d3Smrg switch (cpp) { 2228de2362d3Smrg case 4: 2229de2362d3Smrg tiling_flags |= RADEON_TILING_SWAP_32BIT; 2230de2362d3Smrg break; 2231de2362d3Smrg case 2: 2232de2362d3Smrg tiling_flags |= RADEON_TILING_SWAP_16BIT; 2233de2362d3Smrg break; 2234de2362d3Smrg } 223518781e08Smrg if (info->ChipFamily < CHIP_FAMILY_R600 && 223618781e08Smrg info->r600_shadow_fb && tiling_flags) 223718781e08Smrg tiling_flags |= RADEON_TILING_SURFACE; 2238de2362d3Smrg#endif 2239de2362d3Smrg if (tiling_flags) 2240de2362d3Smrg radeon_bo_set_tiling(info->front_bo, tiling_flags, pitch); 2241de2362d3Smrg 2242de2362d3Smrg if (!info->r600_shadow_fb) { 2243de2362d3Smrg psurface = radeon_get_pixmap_surface(ppix); 2244de2362d3Smrg *psurface = info->front_surface; 2245de2362d3Smrg screen->ModifyPixmapHeader(ppix, 2246de2362d3Smrg width, height, -1, -1, pitch, NULL); 2247de2362d3Smrg } else { 2248de2362d3Smrg if (radeon_bo_map(info->front_bo, 1)) 2249de2362d3Smrg goto fail; 2250de2362d3Smrg fb_shadow = calloc(1, screen_size); 2251de2362d3Smrg if (fb_shadow == NULL) 2252de2362d3Smrg goto fail; 2253de2362d3Smrg free(info->fb_shadow); 2254de2362d3Smrg info->fb_shadow = fb_shadow; 2255de2362d3Smrg screen->ModifyPixmapHeader(ppix, 2256de2362d3Smrg width, height, -1, -1, pitch, 2257de2362d3Smrg info->fb_shadow); 2258de2362d3Smrg } 225918781e08Smrg 226018781e08Smrg if (info->use_glamor) 226118781e08Smrg radeon_glamor_create_screen_resources(scrn->pScreen); 226218781e08Smrg 226318781e08Smrg if (!info->r600_shadow_fb) { 226418781e08Smrg if (!radeon_set_pixmap_bo(ppix, info->front_bo)) 226518781e08Smrg goto fail; 226618781e08Smrg } 226718781e08Smrg 226818781e08Smrg /* Clear new buffer */ 226918781e08Smrg gc = GetScratchGC(ppix->drawable.depth, scrn->pScreen); 227018781e08Smrg force = info->accel_state->force; 227118781e08Smrg info->accel_state->force = TRUE; 227218781e08Smrg ValidateGC(&ppix->drawable, gc); 227318781e08Smrg rect.x = 0; 227418781e08Smrg rect.y = 0; 227518781e08Smrg rect.width = width; 227618781e08Smrg rect.height = height; 227718781e08Smrg (*gc->ops->PolyFillRect)(&ppix->drawable, gc, 1, &rect); 227818781e08Smrg FreeScratchGC(gc); 227918781e08Smrg info->accel_state->force = force; 228018781e08Smrg radeon_cs_flush_indirect(scrn); 228118781e08Smrg radeon_bo_wait(info->front_bo); 22820d16fef4Smrg 2283de2362d3Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 2284de2362d3Smrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 2285de2362d3Smrg 2286de2362d3Smrg if (!crtc->enabled) 2287de2362d3Smrg continue; 2288de2362d3Smrg 2289de2362d3Smrg drmmode_set_mode_major(crtc, &crtc->mode, 2290de2362d3Smrg crtc->rotation, crtc->x, crtc->y); 2291de2362d3Smrg } 2292de2362d3Smrg 2293de2362d3Smrg if (old_fb_id) 2294de2362d3Smrg drmModeRmFB(drmmode->fd, old_fb_id); 2295de2362d3Smrg if (old_front) 2296de2362d3Smrg radeon_bo_unref(old_front); 2297de2362d3Smrg 2298de2362d3Smrg radeon_kms_update_vram_limit(scrn, screen_size); 2299de2362d3Smrg return TRUE; 2300de2362d3Smrg 2301de2362d3Smrg fail: 2302de2362d3Smrg if (info->front_bo) 2303de2362d3Smrg radeon_bo_unref(info->front_bo); 2304de2362d3Smrg info->front_bo = old_front; 2305de2362d3Smrg scrn->virtualX = old_width; 2306de2362d3Smrg scrn->virtualY = old_height; 2307de2362d3Smrg scrn->displayWidth = old_pitch; 2308de2362d3Smrg drmmode->fb_id = old_fb_id; 2309de2362d3Smrg 2310de2362d3Smrg return FALSE; 2311de2362d3Smrg} 2312de2362d3Smrg 2313de2362d3Smrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { 2314de2362d3Smrg drmmode_xf86crtc_resize 2315de2362d3Smrg}; 2316de2362d3Smrg 231718781e08Smrgvoid 231818781e08Smrgdrmmode_clear_pending_flip(xf86CrtcPtr crtc) 231918781e08Smrg{ 232018781e08Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 232118781e08Smrg 232218781e08Smrg drmmode_crtc->flip_pending = FALSE; 232318781e08Smrg 232418781e08Smrg if (!crtc->enabled || 232518781e08Smrg (drmmode_crtc->pending_dpms_mode != DPMSModeOn && 232618781e08Smrg drmmode_crtc->dpms_mode != drmmode_crtc->pending_dpms_mode)) { 232718781e08Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 232818781e08Smrg int o; 232918781e08Smrg 233018781e08Smrg for (o = 0; o < xf86_config->num_output; o++) { 233118781e08Smrg xf86OutputPtr output = xf86_config->output[o]; 233218781e08Smrg 233318781e08Smrg if (output->crtc != crtc) 233418781e08Smrg continue; 233518781e08Smrg 233618781e08Smrg drmmode_output_dpms(output, drmmode_crtc->pending_dpms_mode); 233718781e08Smrg } 233818781e08Smrg 233918781e08Smrg drmmode_crtc_dpms(crtc, drmmode_crtc->pending_dpms_mode); 234018781e08Smrg } 234118781e08Smrg 234218781e08Smrg drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 234318781e08Smrg &drmmode_crtc->scanout_destroy[0]); 234418781e08Smrg drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 234518781e08Smrg &drmmode_crtc->scanout_destroy[1]); 234618781e08Smrg} 234718781e08Smrg 2348de2362d3Smrgstatic void 234918781e08Smrgdrmmode_flip_abort(xf86CrtcPtr crtc, void *event_data) 2350de2362d3Smrg{ 235118781e08Smrg drmmode_flipdata_ptr flipdata = event_data; 235218781e08Smrg 235318781e08Smrg if (--flipdata->flip_count == 0) { 235418781e08Smrg if (!flipdata->fe_crtc) 235518781e08Smrg flipdata->fe_crtc = crtc; 235618781e08Smrg flipdata->abort(flipdata->fe_crtc, flipdata->event_data); 235718781e08Smrg free(flipdata); 235818781e08Smrg } 235918781e08Smrg 236018781e08Smrg drmmode_clear_pending_flip(crtc); 2361de2362d3Smrg} 2362de2362d3Smrg 2363de2362d3Smrgstatic void 236418781e08Smrgdrmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data) 2365de2362d3Smrg{ 236618781e08Smrg RADEONInfoPtr info = RADEONPTR(crtc->scrn); 236718781e08Smrg drmmode_flipdata_ptr flipdata = event_data; 2368de2362d3Smrg 2369de2362d3Smrg /* Is this the event whose info shall be delivered to higher level? */ 237018781e08Smrg if (crtc == flipdata->fe_crtc) { 2371de2362d3Smrg /* Yes: Cache msc, ust for later delivery. */ 2372de2362d3Smrg flipdata->fe_frame = frame; 237318781e08Smrg flipdata->fe_usec = usec; 2374de2362d3Smrg } 2375de2362d3Smrg 237618781e08Smrg if (--flipdata->flip_count == 0) { 237718781e08Smrg /* Deliver MSC & UST from reference/current CRTC to flip event 237818781e08Smrg * handler 237918781e08Smrg */ 238018781e08Smrg if (flipdata->fe_crtc) 238118781e08Smrg flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame, 238218781e08Smrg flipdata->fe_usec, flipdata->event_data); 238318781e08Smrg else 238418781e08Smrg flipdata->handler(crtc, frame, usec, flipdata->event_data); 2385de2362d3Smrg 238618781e08Smrg /* Release framebuffer */ 238718781e08Smrg drmModeRmFB(info->drmmode.fd, flipdata->old_fb_id); 23887821949aSmrg 238918781e08Smrg free(flipdata); 239018781e08Smrg } 2391de2362d3Smrg 239218781e08Smrg drmmode_clear_pending_flip(crtc); 2393de2362d3Smrg} 2394de2362d3Smrg 2395de2362d3Smrg 239618781e08Smrg#if HAVE_NOTIFY_FD 239718781e08Smrgstatic void 239818781e08Smrgdrm_notify_fd(int fd, int ready, void *data) 239918781e08Smrg#else 2400de2362d3Smrgstatic void 2401de2362d3Smrgdrm_wakeup_handler(pointer data, int err, pointer p) 240218781e08Smrg#endif 2403de2362d3Smrg{ 2404de2362d3Smrg drmmode_ptr drmmode = data; 240518781e08Smrg#if !HAVE_NOTIFY_FD 2406de2362d3Smrg fd_set *read_mask = p; 2407de2362d3Smrg 240818781e08Smrg if (err >= 0 && FD_ISSET(drmmode->fd, read_mask)) 240918781e08Smrg#endif 241018781e08Smrg { 2411de2362d3Smrg drmHandleEvent(drmmode->fd, &drmmode->event_context); 2412de2362d3Smrg } 2413de2362d3Smrg} 2414de2362d3Smrg 24153ed65abbSmrgstatic Bool drmmode_probe_page_flip_target(drmmode_ptr drmmode) 24163ed65abbSmrg{ 24173ed65abbSmrg#ifdef DRM_CAP_PAGE_FLIP_TARGET 24183ed65abbSmrg uint64_t cap_value; 24193ed65abbSmrg 24203ed65abbSmrg return drmGetCap(drmmode->fd, DRM_CAP_PAGE_FLIP_TARGET, 24213ed65abbSmrg &cap_value) == 0 && cap_value != 0; 24223ed65abbSmrg#else 24233ed65abbSmrg return FALSE; 24243ed65abbSmrg#endif 24253ed65abbSmrg} 24263ed65abbSmrg 24273ed65abbSmrgstatic int 24283ed65abbSmrgdrmmode_page_flip(drmmode_crtc_private_ptr drmmode_crtc, int fb_id, 24293ed65abbSmrg uint32_t flags, uintptr_t drm_queue_seq) 24303ed65abbSmrg{ 24313ed65abbSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 24323ed65abbSmrg 24333ed65abbSmrg flags |= DRM_MODE_PAGE_FLIP_EVENT; 24343ed65abbSmrg return drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 24353ed65abbSmrg fb_id, flags, (void*)drm_queue_seq); 24363ed65abbSmrg} 24373ed65abbSmrg 24383ed65abbSmrgint 24393ed65abbSmrgdrmmode_page_flip_target_absolute(RADEONEntPtr pRADEONEnt, 24403ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc, 24413ed65abbSmrg int fb_id, uint32_t flags, 24423ed65abbSmrg uintptr_t drm_queue_seq, uint32_t target_msc) 24433ed65abbSmrg{ 24443ed65abbSmrg#ifdef DRM_MODE_PAGE_FLIP_TARGET 24453ed65abbSmrg if (pRADEONEnt->has_page_flip_target) { 24463ed65abbSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 24473ed65abbSmrg 24483ed65abbSmrg flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE; 24493ed65abbSmrg return drmModePageFlipTarget(drmmode->fd, 24503ed65abbSmrg drmmode_crtc->mode_crtc->crtc_id, 24513ed65abbSmrg fb_id, flags, (void*)drm_queue_seq, 24523ed65abbSmrg target_msc); 24533ed65abbSmrg } 24543ed65abbSmrg#endif 24553ed65abbSmrg 24563ed65abbSmrg return drmmode_page_flip(drmmode_crtc, fb_id, flags, drm_queue_seq); 24573ed65abbSmrg} 24583ed65abbSmrg 24593ed65abbSmrgint 24603ed65abbSmrgdrmmode_page_flip_target_relative(RADEONEntPtr pRADEONEnt, 24613ed65abbSmrg drmmode_crtc_private_ptr drmmode_crtc, 24623ed65abbSmrg int fb_id, uint32_t flags, 24633ed65abbSmrg uintptr_t drm_queue_seq, uint32_t target_msc) 24643ed65abbSmrg{ 24653ed65abbSmrg#ifdef DRM_MODE_PAGE_FLIP_TARGET 24663ed65abbSmrg if (pRADEONEnt->has_page_flip_target) { 24673ed65abbSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 24683ed65abbSmrg 24693ed65abbSmrg flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE; 24703ed65abbSmrg return drmModePageFlipTarget(drmmode->fd, 24713ed65abbSmrg drmmode_crtc->mode_crtc->crtc_id, 24723ed65abbSmrg fb_id, flags, (void*)drm_queue_seq, 24733ed65abbSmrg target_msc); 24743ed65abbSmrg } 24753ed65abbSmrg#endif 24763ed65abbSmrg 24773ed65abbSmrg return drmmode_page_flip(drmmode_crtc, fb_id, flags, drm_queue_seq); 24783ed65abbSmrg} 24793ed65abbSmrg 2480de2362d3SmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) 2481de2362d3Smrg{ 248218781e08Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 248318781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 2484de2362d3Smrg int i, num_dvi = 0, num_hdmi = 0; 248518781e08Smrg drmModeResPtr mode_res; 248618781e08Smrg unsigned int crtcs_needed = 0; 248718781e08Smrg#ifdef RADEON_PIXMAP_SHARING 248818781e08Smrg char *bus_id_string, *provider_name; 248918781e08Smrg#endif 2490de2362d3Smrg 2491de2362d3Smrg xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); 2492de2362d3Smrg 2493de2362d3Smrg drmmode->scrn = pScrn; 2494de2362d3Smrg drmmode->cpp = cpp; 249518781e08Smrg mode_res = drmModeGetResources(drmmode->fd); 249618781e08Smrg if (!mode_res) 2497de2362d3Smrg return FALSE; 2498de2362d3Smrg 249918781e08Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 250018781e08Smrg "Initializing outputs ...\n"); 250118781e08Smrg for (i = 0; i < mode_res->count_connectors; i++) 250218781e08Smrg crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, 250318781e08Smrg i, &num_dvi, &num_hdmi, 0); 250418781e08Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 250518781e08Smrg "%d crtcs needed for screen.\n", crtcs_needed); 250618781e08Smrg 250718781e08Smrg if (info->r600_shadow_fb) { 250818781e08Smrg /* Rotation requires hardware acceleration */ 250918781e08Smrg drmmode_crtc_funcs.shadow_allocate = NULL; 251018781e08Smrg drmmode_crtc_funcs.shadow_create = NULL; 251118781e08Smrg drmmode_crtc_funcs.shadow_destroy = NULL; 251218781e08Smrg } 251318781e08Smrg 251418781e08Smrg drmmode->count_crtcs = mode_res->count_crtcs; 251518781e08Smrg xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, mode_res->max_height); 251618781e08Smrg 251718781e08Smrg for (i = 0; i < mode_res->count_crtcs; i++) 251818781e08Smrg if (!xf86IsEntityShared(pScrn->entityList[0]) || 251918781e08Smrg (crtcs_needed && !(pRADEONEnt->assigned_crtcs & (1 << i)))) 252018781e08Smrg crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i); 2521de2362d3Smrg 252218781e08Smrg /* All ZaphodHeads outputs provided with matching crtcs? */ 252318781e08Smrg if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0)) 252418781e08Smrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 252518781e08Smrg "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n", 252618781e08Smrg crtcs_needed); 2527de2362d3Smrg 2528de2362d3Smrg /* workout clones */ 252918781e08Smrg drmmode_clones_init(pScrn, drmmode, mode_res); 253018781e08Smrg 253118781e08Smrg#ifdef RADEON_PIXMAP_SHARING 253218781e08Smrg bus_id_string = DRICreatePCIBusID(info->PciInfo); 253318781e08Smrg XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, bus_id_string); 253418781e08Smrg free(bus_id_string); 253518781e08Smrg xf86ProviderSetup(pScrn, NULL, provider_name); 253618781e08Smrg free(provider_name); 253718781e08Smrg#endif 2538de2362d3Smrg 2539de2362d3Smrg xf86InitialConfiguration(pScrn, TRUE); 2540de2362d3Smrg 2541de2362d3Smrg drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION; 254218781e08Smrg drmmode->event_context.vblank_handler = radeon_drm_queue_handler; 254318781e08Smrg drmmode->event_context.page_flip_handler = radeon_drm_queue_handler; 2544de2362d3Smrg 25453ed65abbSmrg pRADEONEnt->has_page_flip_target = drmmode_probe_page_flip_target(drmmode); 25463ed65abbSmrg 254718781e08Smrg drmModeFreeResources(mode_res); 2548de2362d3Smrg return TRUE; 2549de2362d3Smrg} 2550de2362d3Smrg 2551de2362d3Smrgvoid drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 2552de2362d3Smrg{ 2553de2362d3Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 2554de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 2555de2362d3Smrg 255618781e08Smrg if (info->dri2.pKernelDRMVersion->version_minor < 4) 255718781e08Smrg return; 255818781e08Smrg 255918781e08Smrg info->drmmode_inited = TRUE; 256018781e08Smrg if (pRADEONEnt->fd_wakeup_registered != serverGeneration) { 256118781e08Smrg#if HAVE_NOTIFY_FD 256218781e08Smrg SetNotifyFd(drmmode->fd, drm_notify_fd, X_NOTIFY_READ, drmmode); 256318781e08Smrg#else 2564de2362d3Smrg AddGeneralSocket(drmmode->fd); 2565de2362d3Smrg RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, 2566de2362d3Smrg drm_wakeup_handler, drmmode); 256718781e08Smrg#endif 2568de2362d3Smrg pRADEONEnt->fd_wakeup_registered = serverGeneration; 256918781e08Smrg pRADEONEnt->fd_wakeup_ref = 1; 257018781e08Smrg } else 257118781e08Smrg pRADEONEnt->fd_wakeup_ref++; 257218781e08Smrg} 257318781e08Smrg 257418781e08Smrgvoid drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 257518781e08Smrg{ 257618781e08Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 257718781e08Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 257818781e08Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 257918781e08Smrg int c; 258018781e08Smrg 258118781e08Smrg if (info->dri2.pKernelDRMVersion->version_minor < 4 || !info->drmmode_inited) 258218781e08Smrg return; 258318781e08Smrg 258418781e08Smrg if (pRADEONEnt->fd_wakeup_registered == serverGeneration && 258518781e08Smrg !--pRADEONEnt->fd_wakeup_ref) { 258618781e08Smrg#if HAVE_NOTIFY_FD 258718781e08Smrg RemoveNotifyFd(drmmode->fd); 258818781e08Smrg#else 258918781e08Smrg RemoveGeneralSocket(drmmode->fd); 259018781e08Smrg RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, 259118781e08Smrg drm_wakeup_handler, drmmode); 259218781e08Smrg#endif 259318781e08Smrg } 259418781e08Smrg 25953ed65abbSmrg for (c = 0; c < config->num_crtc; c++) 25963ed65abbSmrg drmmode_crtc_scanout_free(config->crtc[c]->driver_private); 2597de2362d3Smrg} 2598de2362d3Smrg 259918781e08Smrg 2600de2362d3SmrgBool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, struct radeon_bo_manager *bufmgr) 2601de2362d3Smrg{ 2602de2362d3Smrg drmmode->bufmgr = bufmgr; 2603de2362d3Smrg return TRUE; 2604de2362d3Smrg} 2605de2362d3Smrg 2606de2362d3Smrg 2607de2362d3Smrg 2608de2362d3Smrgvoid drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id, struct radeon_bo *bo) 2609de2362d3Smrg{ 2610de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2611de2362d3Smrg xf86CrtcPtr crtc = xf86_config->crtc[id]; 2612de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 2613de2362d3Smrg 2614de2362d3Smrg drmmode_crtc->cursor_bo = bo; 2615de2362d3Smrg} 2616de2362d3Smrg 2617de2362d3Smrgvoid drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y) 2618de2362d3Smrg{ 2619de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 2620de2362d3Smrg xf86OutputPtr output = config->output[config->compat_output]; 2621de2362d3Smrg xf86CrtcPtr crtc = output->crtc; 2622de2362d3Smrg 2623de2362d3Smrg if (crtc && crtc->enabled) { 2624de2362d3Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 2625de2362d3Smrg x, y); 2626de2362d3Smrg } 2627de2362d3Smrg} 2628de2362d3Smrg 262918781e08SmrgBool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, 263018781e08Smrg Bool set_hw) 2631de2362d3Smrg{ 2632de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 2633de2362d3Smrg int c; 2634de2362d3Smrg 2635de2362d3Smrg for (c = 0; c < config->num_crtc; c++) { 2636de2362d3Smrg xf86CrtcPtr crtc = config->crtc[c]; 2637de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 2638de2362d3Smrg xf86OutputPtr output = NULL; 2639de2362d3Smrg int o; 2640de2362d3Smrg 2641de2362d3Smrg /* Skip disabled CRTCs */ 2642de2362d3Smrg if (!crtc->enabled) { 264318781e08Smrg if (set_hw) { 264418781e08Smrg drmmode_do_crtc_dpms(crtc, DPMSModeOff); 264518781e08Smrg drmModeSetCrtc(drmmode->fd, 264618781e08Smrg drmmode_crtc->mode_crtc->crtc_id, 264718781e08Smrg 0, 0, 0, NULL, 0, NULL); 264818781e08Smrg } 2649de2362d3Smrg continue; 2650de2362d3Smrg } 2651de2362d3Smrg 2652de2362d3Smrg if (config->output[config->compat_output]->crtc == crtc) 2653de2362d3Smrg output = config->output[config->compat_output]; 2654de2362d3Smrg else 2655de2362d3Smrg { 2656de2362d3Smrg for (o = 0; o < config->num_output; o++) 2657de2362d3Smrg if (config->output[o]->crtc == crtc) 2658de2362d3Smrg { 2659de2362d3Smrg output = config->output[o]; 2660de2362d3Smrg break; 2661de2362d3Smrg } 2662de2362d3Smrg } 2663de2362d3Smrg /* paranoia */ 2664de2362d3Smrg if (!output) 2665de2362d3Smrg continue; 2666de2362d3Smrg 2667de2362d3Smrg /* Mark that we'll need to re-set the mode for sure */ 2668de2362d3Smrg memset(&crtc->mode, 0, sizeof(crtc->mode)); 2669de2362d3Smrg if (!crtc->desiredMode.CrtcHDisplay) 2670de2362d3Smrg { 2671de2362d3Smrg DisplayModePtr mode = xf86OutputFindClosestMode (output, pScrn->currentMode); 2672de2362d3Smrg 2673de2362d3Smrg if (!mode) 2674de2362d3Smrg return FALSE; 2675de2362d3Smrg crtc->desiredMode = *mode; 2676de2362d3Smrg crtc->desiredRotation = RR_Rotate_0; 2677de2362d3Smrg crtc->desiredX = 0; 2678de2362d3Smrg crtc->desiredY = 0; 2679de2362d3Smrg } 2680de2362d3Smrg 268118781e08Smrg if (set_hw) { 268218781e08Smrg if (!crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, crtc->desiredRotation, 268318781e08Smrg crtc->desiredX, crtc->desiredY)) 268418781e08Smrg return FALSE; 268518781e08Smrg } else { 268618781e08Smrg crtc->mode = crtc->desiredMode; 268718781e08Smrg crtc->rotation = crtc->desiredRotation; 268818781e08Smrg crtc->x = crtc->desiredX; 268918781e08Smrg crtc->y = crtc->desiredY; 269018781e08Smrg if (!drmmode_handle_transform(crtc)) 269118781e08Smrg return FALSE; 269218781e08Smrg } 2693de2362d3Smrg } 2694de2362d3Smrg return TRUE; 2695de2362d3Smrg} 2696de2362d3Smrg 269718781e08SmrgBool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn) 2698de2362d3Smrg{ 2699de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2700de2362d3Smrg 270118781e08Smrg if (xf86_config->num_crtc) { 270218781e08Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 270318781e08Smrg "Initializing kms color map\n"); 270418781e08Smrg if (!miCreateDefColormap(pScreen)) 270518781e08Smrg return FALSE; 270618781e08Smrg /* all radeons support 10 bit CLUTs */ 270718781e08Smrg if (!xf86HandleColormaps(pScreen, 256, 10, 270818781e08Smrg NULL, NULL, 270918781e08Smrg CMAP_PALETTED_TRUECOLOR 271018781e08Smrg#if 0 /* This option messes up text mode! (eich@suse.de) */ 271118781e08Smrg | CMAP_LOAD_EVEN_IF_OFFSCREEN 271218781e08Smrg#endif 271318781e08Smrg | CMAP_RELOAD_ON_MODE_SWITCH)) 271418781e08Smrg return FALSE; 271518781e08Smrg } 271618781e08Smrg return TRUE; 271718781e08Smrg} 27187314432eSmrg 271918781e08Smrgstatic Bool 272018781e08Smrgdrmmode_find_output(ScrnInfoPtr scrn, int output_id, int *num_dvi, 272118781e08Smrg int *num_hdmi) 272218781e08Smrg{ 272318781e08Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 272418781e08Smrg int i; 27257314432eSmrg 272618781e08Smrg for (i = 0; i < config->num_output; i++) { 272718781e08Smrg xf86OutputPtr output = config->output[i]; 272818781e08Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 272918781e08Smrg 273018781e08Smrg if (drmmode_output->output_id == output_id) { 273118781e08Smrg switch(drmmode_output->mode_output->connector_type) { 273218781e08Smrg case DRM_MODE_CONNECTOR_DVII: 273318781e08Smrg case DRM_MODE_CONNECTOR_DVID: 273418781e08Smrg case DRM_MODE_CONNECTOR_DVIA: 273518781e08Smrg (*num_dvi)++; 273618781e08Smrg break; 273718781e08Smrg case DRM_MODE_CONNECTOR_HDMIA: 273818781e08Smrg case DRM_MODE_CONNECTOR_HDMIB: 273918781e08Smrg (*num_hdmi)++; 274018781e08Smrg break; 274118781e08Smrg } 274218781e08Smrg 274318781e08Smrg return TRUE; 274418781e08Smrg } 274518781e08Smrg } 274618781e08Smrg 274718781e08Smrg return FALSE; 27487314432eSmrg} 27497314432eSmrg 275018781e08Smrgvoid 275118781e08Smrgradeon_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode) 27520d16fef4Smrg{ 275318781e08Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 275418781e08Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 275518781e08Smrg drmModeResPtr mode_res; 275618781e08Smrg int i, j; 275718781e08Smrg Bool found; 275818781e08Smrg Bool changed = FALSE; 275918781e08Smrg int num_dvi = 0, num_hdmi = 0; 276018781e08Smrg 276118781e08Smrg mode_res = drmModeGetResources(drmmode->fd); 276218781e08Smrg if (!mode_res) 276318781e08Smrg goto out; 276418781e08Smrg 276518781e08Smrgrestart_destroy: 276618781e08Smrg for (i = 0; i < config->num_output; i++) { 276718781e08Smrg xf86OutputPtr output = config->output[i]; 276818781e08Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 276918781e08Smrg found = FALSE; 277018781e08Smrg for (j = 0; j < mode_res->count_connectors; j++) { 277118781e08Smrg if (mode_res->connectors[j] == drmmode_output->output_id) { 277218781e08Smrg found = TRUE; 277318781e08Smrg break; 277418781e08Smrg } 277518781e08Smrg } 277618781e08Smrg if (found) 277718781e08Smrg continue; 277818781e08Smrg 277918781e08Smrg drmModeFreeConnector(drmmode_output->mode_output); 278018781e08Smrg drmmode_output->mode_output = NULL; 278118781e08Smrg drmmode_output->output_id = -1; 278218781e08Smrg 278318781e08Smrg changed = TRUE; 278418781e08Smrg if (drmmode->delete_dp_12_displays) { 278518781e08Smrg RROutputDestroy(output->randr_output); 278618781e08Smrg xf86OutputDestroy(output); 278718781e08Smrg goto restart_destroy; 278818781e08Smrg } 278918781e08Smrg } 279018781e08Smrg 279118781e08Smrg /* find new output ids we don't have outputs for */ 279218781e08Smrg for (i = 0; i < mode_res->count_connectors; i++) { 279318781e08Smrg if (drmmode_find_output(pRADEONEnt->primary_scrn, 279418781e08Smrg mode_res->connectors[i], 279518781e08Smrg &num_dvi, &num_hdmi) || 279618781e08Smrg (pRADEONEnt->secondary_scrn && 279718781e08Smrg drmmode_find_output(pRADEONEnt->secondary_scrn, 279818781e08Smrg mode_res->connectors[i], 279918781e08Smrg &num_dvi, &num_hdmi))) 280018781e08Smrg continue; 280118781e08Smrg 280218781e08Smrg if (drmmode_output_init(scrn, drmmode, mode_res, i, &num_dvi, 280318781e08Smrg &num_hdmi, 1) != 0) 280418781e08Smrg changed = TRUE; 280518781e08Smrg } 280618781e08Smrg 280718781e08Smrg if (changed && dixPrivateKeyRegistered(rrPrivKey)) { 280818781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0) 280918781e08Smrg RRSetChanged(xf86ScrnToScreen(scrn)); 281018781e08Smrg#else 281118781e08Smrg rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen); 281218781e08Smrg rrScrPriv->changed = TRUE; 28130d16fef4Smrg#endif 281418781e08Smrg RRTellChanged(xf86ScrnToScreen(scrn)); 281518781e08Smrg } 28167821949aSmrg 281718781e08Smrg drmModeFreeResources(mode_res); 281818781e08Smrgout: 281918781e08Smrg RRGetInfo(xf86ScrnToScreen(scrn), TRUE); 282018781e08Smrg} 2821de2362d3Smrg#ifdef HAVE_LIBUDEV 2822de2362d3Smrgstatic void 2823de2362d3Smrgdrmmode_handle_uevents(int fd, void *closure) 2824de2362d3Smrg{ 2825de2362d3Smrg drmmode_ptr drmmode = closure; 2826de2362d3Smrg ScrnInfoPtr scrn = drmmode->scrn; 2827de2362d3Smrg struct udev_device *dev; 282818781e08Smrg Bool received = FALSE; 28293ed65abbSmrg struct timeval tv = { 0, 0 }; 28303ed65abbSmrg fd_set readfd; 28313ed65abbSmrg 28323ed65abbSmrg FD_ZERO(&readfd); 28333ed65abbSmrg FD_SET(fd, &readfd); 28343ed65abbSmrg 28353ed65abbSmrg while (select(fd + 1, &readfd, NULL, NULL, &tv) > 0 && 28363ed65abbSmrg FD_ISSET(fd, &readfd)) { 28373ed65abbSmrg /* select() ensured that this will not block */ 28383ed65abbSmrg dev = udev_monitor_receive_device(drmmode->uevent_monitor); 28393ed65abbSmrg if (dev) { 28403ed65abbSmrg udev_device_unref(dev); 28413ed65abbSmrg received = TRUE; 28423ed65abbSmrg } 284318781e08Smrg } 284418781e08Smrg 284518781e08Smrg if (received) 284618781e08Smrg radeon_mode_hotplug(scrn, drmmode); 2847de2362d3Smrg} 2848de2362d3Smrg#endif 2849de2362d3Smrg 2850de2362d3Smrgvoid drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 2851de2362d3Smrg{ 2852de2362d3Smrg#ifdef HAVE_LIBUDEV 2853de2362d3Smrg struct udev *u; 2854de2362d3Smrg struct udev_monitor *mon; 2855de2362d3Smrg 2856de2362d3Smrg u = udev_new(); 2857de2362d3Smrg if (!u) 2858de2362d3Smrg return; 2859de2362d3Smrg mon = udev_monitor_new_from_netlink(u, "udev"); 2860de2362d3Smrg if (!mon) { 2861de2362d3Smrg udev_unref(u); 2862de2362d3Smrg return; 2863de2362d3Smrg } 2864de2362d3Smrg 2865de2362d3Smrg if (udev_monitor_filter_add_match_subsystem_devtype(mon, 2866de2362d3Smrg "drm", 2867de2362d3Smrg "drm_minor") < 0 || 2868de2362d3Smrg udev_monitor_enable_receiving(mon) < 0) { 2869de2362d3Smrg udev_monitor_unref(mon); 2870de2362d3Smrg udev_unref(u); 2871de2362d3Smrg return; 2872de2362d3Smrg } 2873de2362d3Smrg 2874de2362d3Smrg drmmode->uevent_handler = 2875de2362d3Smrg xf86AddGeneralHandler(udev_monitor_get_fd(mon), 2876de2362d3Smrg drmmode_handle_uevents, 2877de2362d3Smrg drmmode); 2878de2362d3Smrg 2879de2362d3Smrg drmmode->uevent_monitor = mon; 2880de2362d3Smrg#endif 2881de2362d3Smrg} 2882de2362d3Smrg 2883de2362d3Smrgvoid drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) 2884de2362d3Smrg{ 2885de2362d3Smrg#ifdef HAVE_LIBUDEV 2886de2362d3Smrg if (drmmode->uevent_handler) { 2887de2362d3Smrg struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); 2888de2362d3Smrg xf86RemoveGeneralHandler(drmmode->uevent_handler); 2889de2362d3Smrg 2890de2362d3Smrg udev_monitor_unref(drmmode->uevent_monitor); 2891de2362d3Smrg udev_unref(u); 2892de2362d3Smrg } 2893de2362d3Smrg#endif 2894de2362d3Smrg} 2895de2362d3Smrg 289618781e08SmrgBool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, 289718781e08Smrg uint32_t new_front_handle, uint64_t id, void *data, 289818781e08Smrg int ref_crtc_hw_id, radeon_drm_handler_proc handler, 289918781e08Smrg radeon_drm_abort_proc abort, 29003ed65abbSmrg enum drmmode_flip_sync flip_sync, 29013ed65abbSmrg uint32_t target_msc) 2902de2362d3Smrg{ 29033ed65abbSmrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn); 2904de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 2905de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 290618781e08Smrg xf86CrtcPtr crtc = NULL; 2907de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; 2908de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 2909de2362d3Smrg unsigned int pitch; 291018781e08Smrg int i; 2911de2362d3Smrg uint32_t tiling_flags = 0; 29123ed65abbSmrg uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0; 2913de2362d3Smrg drmmode_flipdata_ptr flipdata; 291418781e08Smrg uintptr_t drm_queue_seq = 0; 2915de2362d3Smrg 2916de2362d3Smrg if (info->allowColorTiling) { 2917de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) 2918de2362d3Smrg tiling_flags |= RADEON_TILING_MICRO; 2919de2362d3Smrg else 2920de2362d3Smrg tiling_flags |= RADEON_TILING_MACRO; 2921de2362d3Smrg } 2922de2362d3Smrg 292318781e08Smrg pitch = RADEON_ALIGN(scrn->displayWidth, drmmode_get_pitch_align(scrn, info->pixel_bytes, tiling_flags)) * 292418781e08Smrg info->pixel_bytes; 2925de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) { 2926de2362d3Smrg pitch = info->front_surface.level[0].pitch_bytes; 2927de2362d3Smrg } 2928de2362d3Smrg 29297821949aSmrg flipdata = calloc(1, sizeof(drmmode_flipdata_rec)); 29307821949aSmrg if (!flipdata) { 29317821949aSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 29327821949aSmrg "flip queue: data alloc failed.\n"); 293318781e08Smrg goto error; 29347821949aSmrg } 293518781e08Smrg 293618781e08Smrg /* 293718781e08Smrg * Create a new handle for the back buffer 293818781e08Smrg */ 293918781e08Smrg flipdata->old_fb_id = drmmode->fb_id; 294018781e08Smrg if (drmModeAddFB(drmmode->fd, scrn->virtualX, scrn->virtualY, 294118781e08Smrg scrn->depth, scrn->bitsPerPixel, pitch, 294218781e08Smrg new_front_handle, &drmmode->fb_id)) 294318781e08Smrg goto error; 294418781e08Smrg 2945de2362d3Smrg /* 2946de2362d3Smrg * Queue flips on all enabled CRTCs 2947de2362d3Smrg * Note that if/when we get per-CRTC buffers, we'll have to update this. 2948de2362d3Smrg * Right now it assumes a single shared fb across all CRTCs, with the 2949de2362d3Smrg * kernel fixing up the offset of each CRTC as necessary. 2950de2362d3Smrg * 2951de2362d3Smrg * Also, flips queued on disabled or incorrectly configured displays 2952de2362d3Smrg * may never complete; this is a configuration error. 2953de2362d3Smrg */ 2954de2362d3Smrg 2955de2362d3Smrg flipdata->event_data = data; 295618781e08Smrg flipdata->handler = handler; 295718781e08Smrg flipdata->abort = abort; 295818781e08Smrg 2959de2362d3Smrg for (i = 0; i < config->num_crtc; i++) { 296018781e08Smrg crtc = config->crtc[i]; 296118781e08Smrg 296218781e08Smrg if (!crtc->enabled) 2963de2362d3Smrg continue; 2964de2362d3Smrg 2965de2362d3Smrg flipdata->flip_count++; 296618781e08Smrg drmmode_crtc = crtc->driver_private; 2967de2362d3Smrg 2968de2362d3Smrg /* Only the reference crtc will finally deliver its page flip 2969de2362d3Smrg * completion event. All other crtc's events will be discarded. 2970de2362d3Smrg */ 297118781e08Smrg if (drmmode_crtc->hw_id == ref_crtc_hw_id) 297218781e08Smrg flipdata->fe_crtc = crtc; 297318781e08Smrg 297418781e08Smrg drm_queue_seq = radeon_drm_queue_alloc(crtc, client, id, 297518781e08Smrg flipdata, 297618781e08Smrg drmmode_flip_handler, 297718781e08Smrg drmmode_flip_abort); 297818781e08Smrg if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { 297918781e08Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 298018781e08Smrg "Allocating DRM queue event entry failed.\n"); 298118781e08Smrg goto error; 298218781e08Smrg } 2983de2362d3Smrg 29843ed65abbSmrg if (drmmode_crtc->hw_id == ref_crtc_hw_id) { 29853ed65abbSmrg if (drmmode_page_flip_target_absolute(pRADEONEnt, 29863ed65abbSmrg drmmode_crtc, 29873ed65abbSmrg drmmode->fb_id, 29883ed65abbSmrg flip_flags, 29893ed65abbSmrg drm_queue_seq, 29903ed65abbSmrg target_msc) != 0) 29913ed65abbSmrg goto flip_error; 29923ed65abbSmrg } else { 29933ed65abbSmrg if (drmmode_page_flip_target_relative(pRADEONEnt, 29943ed65abbSmrg drmmode_crtc, 29953ed65abbSmrg drmmode->fb_id, 29963ed65abbSmrg flip_flags, 29973ed65abbSmrg drm_queue_seq, 0) != 0) 29983ed65abbSmrg goto flip_error; 2999de2362d3Smrg } 30003ed65abbSmrg 300118781e08Smrg drmmode_crtc->flip_pending = TRUE; 300218781e08Smrg drm_queue_seq = 0; 3003de2362d3Smrg } 3004de2362d3Smrg 300518781e08Smrg if (flipdata->flip_count > 0) 300618781e08Smrg return TRUE; 30070d16fef4Smrg 30083ed65abbSmrgflip_error: 30093ed65abbSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n", 30103ed65abbSmrg strerror(errno)); 30113ed65abbSmrg 301218781e08Smrgerror: 30133ed65abbSmrg if (flipdata && flipdata->flip_count <= 1 && 30143ed65abbSmrg drmmode->fb_id != flipdata->old_fb_id) { 301518781e08Smrg drmModeRmFB(drmmode->fd, drmmode->fb_id); 301618781e08Smrg drmmode->fb_id = flipdata->old_fb_id; 301718781e08Smrg } 301818781e08Smrg 301918781e08Smrg if (drm_queue_seq) 302018781e08Smrg radeon_drm_abort_entry(drm_queue_seq); 302118781e08Smrg else if (crtc) 302218781e08Smrg drmmode_flip_abort(crtc, flipdata); 30233ed65abbSmrg else { 30243ed65abbSmrg abort(NULL, data); 302518781e08Smrg free(flipdata); 30263ed65abbSmrg } 3027de2362d3Smrg 3028de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", 3029de2362d3Smrg strerror(errno)); 3030de2362d3Smrg return FALSE; 3031de2362d3Smrg} 3032