drmmode_display.c revision de2362d3
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> 34de2362d3Smrg#include <time.h> 35de2362d3Smrg#include "micmap.h" 36de2362d3Smrg#include "xf86cmap.h" 37de2362d3Smrg#include "radeon.h" 38de2362d3Smrg#include "radeon_reg.h" 39de2362d3Smrg#include "sarea.h" 40de2362d3Smrg 41de2362d3Smrg#include "drmmode_display.h" 42de2362d3Smrg 43de2362d3Smrg/* DPMS */ 44de2362d3Smrg#ifdef HAVE_XEXTPROTO_71 45de2362d3Smrg#include <X11/extensions/dpmsconst.h> 46de2362d3Smrg#else 47de2362d3Smrg#define DPMS_SERVER 48de2362d3Smrg#include <X11/extensions/dpms.h> 49de2362d3Smrg#endif 50de2362d3Smrg 51de2362d3Smrg#define DEFAULT_NOMINAL_FRAME_RATE 60 52de2362d3Smrg 53de2362d3Smrgstatic Bool 54de2362d3Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height); 55de2362d3Smrg 56de2362d3Smrgstatic Bool 57de2362d3SmrgRADEONZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name) 58de2362d3Smrg{ 59de2362d3Smrg int i = 0; 60de2362d3Smrg char s1[20]; 61de2362d3Smrg 62de2362d3Smrg do { 63de2362d3Smrg switch(*s) { 64de2362d3Smrg case ',': 65de2362d3Smrg s1[i] = '\0'; 66de2362d3Smrg i = 0; 67de2362d3Smrg if (strcmp(s1, output_name) == 0) 68de2362d3Smrg return TRUE; 69de2362d3Smrg break; 70de2362d3Smrg case ' ': 71de2362d3Smrg case '\t': 72de2362d3Smrg case '\n': 73de2362d3Smrg case '\r': 74de2362d3Smrg break; 75de2362d3Smrg default: 76de2362d3Smrg s1[i] = *s; 77de2362d3Smrg i++; 78de2362d3Smrg break; 79de2362d3Smrg } 80de2362d3Smrg } while(*s++); 81de2362d3Smrg 82de2362d3Smrg s1[i] = '\0'; 83de2362d3Smrg if (strcmp(s1, output_name) == 0) 84de2362d3Smrg return TRUE; 85de2362d3Smrg 86de2362d3Smrg return FALSE; 87de2362d3Smrg} 88de2362d3Smrg 89de2362d3Smrgstatic PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn, 90de2362d3Smrg int width, int height, 91de2362d3Smrg int depth, int bpp, 92de2362d3Smrg int pitch, int tiling, 93de2362d3Smrg struct radeon_bo *bo, struct radeon_surface *psurf) 94de2362d3Smrg{ 95de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 96de2362d3Smrg ScreenPtr pScreen = pScrn->pScreen; 97de2362d3Smrg PixmapPtr pixmap; 98de2362d3Smrg struct radeon_surface *surface; 99de2362d3Smrg 100de2362d3Smrg pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0); 101de2362d3Smrg if (!pixmap) 102de2362d3Smrg return NULL; 103de2362d3Smrg 104de2362d3Smrg if (!(*pScreen->ModifyPixmapHeader)(pixmap, width, height, 105de2362d3Smrg depth, bpp, pitch, NULL)) { 106de2362d3Smrg return NULL; 107de2362d3Smrg } 108de2362d3Smrg 109de2362d3Smrg if (!info->use_glamor) 110de2362d3Smrg exaMoveInPixmap(pixmap); 111de2362d3Smrg radeon_set_pixmap_bo(pixmap, bo); 112de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 113de2362d3Smrg surface = radeon_get_pixmap_surface(pixmap); 114de2362d3Smrg if (surface && psurf) 115de2362d3Smrg *surface = *psurf; 116de2362d3Smrg else if (surface) { 117de2362d3Smrg memset(surface, 0, sizeof(struct radeon_surface)); 118de2362d3Smrg surface->npix_x = width; 119de2362d3Smrg surface->npix_y = height; 120de2362d3Smrg surface->npix_z = 1; 121de2362d3Smrg surface->blk_w = 1; 122de2362d3Smrg surface->blk_h = 1; 123de2362d3Smrg surface->blk_d = 1; 124de2362d3Smrg surface->array_size = 1; 125de2362d3Smrg surface->last_level = 0; 126de2362d3Smrg surface->bpe = bpp / 8; 127de2362d3Smrg surface->nsamples = 1; 128de2362d3Smrg surface->flags = RADEON_SURF_SCANOUT; 129de2362d3Smrg /* we are requiring a recent enough libdrm version */ 130de2362d3Smrg surface->flags |= RADEON_SURF_HAS_TILE_MODE_INDEX; 131de2362d3Smrg surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); 132de2362d3Smrg surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR_ALIGNED, MODE); 133de2362d3Smrg if (tiling & RADEON_TILING_MICRO) { 134de2362d3Smrg surface->flags = RADEON_SURF_CLR(surface->flags, MODE); 135de2362d3Smrg surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE); 136de2362d3Smrg } 137de2362d3Smrg if (tiling & RADEON_TILING_MACRO) { 138de2362d3Smrg surface->flags = RADEON_SURF_CLR(surface->flags, MODE); 139de2362d3Smrg surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE); 140de2362d3Smrg } 141de2362d3Smrg if (radeon_surface_best(info->surf_man, surface)) { 142de2362d3Smrg return NULL; 143de2362d3Smrg } 144de2362d3Smrg if (radeon_surface_init(info->surf_man, surface)) { 145de2362d3Smrg return NULL; 146de2362d3Smrg } 147de2362d3Smrg } 148de2362d3Smrg } 149de2362d3Smrg 150de2362d3Smrg if (!radeon_glamor_create_textured_pixmap(pixmap)) { 151de2362d3Smrg pScreen->DestroyPixmap(pixmap); 152de2362d3Smrg return NULL; 153de2362d3Smrg } 154de2362d3Smrg 155de2362d3Smrg return pixmap; 156de2362d3Smrg} 157de2362d3Smrg 158de2362d3Smrgstatic void drmmode_destroy_bo_pixmap(PixmapPtr pixmap) 159de2362d3Smrg{ 160de2362d3Smrg ScreenPtr pScreen = pixmap->drawable.pScreen; 161de2362d3Smrg 162de2362d3Smrg (*pScreen->DestroyPixmap)(pixmap); 163de2362d3Smrg} 164de2362d3Smrg 165de2362d3Smrgstatic void 166de2362d3Smrgdrmmode_ConvertFromKMode(ScrnInfoPtr scrn, 167de2362d3Smrg drmModeModeInfo *kmode, 168de2362d3Smrg DisplayModePtr mode) 169de2362d3Smrg{ 170de2362d3Smrg memset(mode, 0, sizeof(DisplayModeRec)); 171de2362d3Smrg mode->status = MODE_OK; 172de2362d3Smrg 173de2362d3Smrg mode->Clock = kmode->clock; 174de2362d3Smrg 175de2362d3Smrg mode->HDisplay = kmode->hdisplay; 176de2362d3Smrg mode->HSyncStart = kmode->hsync_start; 177de2362d3Smrg mode->HSyncEnd = kmode->hsync_end; 178de2362d3Smrg mode->HTotal = kmode->htotal; 179de2362d3Smrg mode->HSkew = kmode->hskew; 180de2362d3Smrg 181de2362d3Smrg mode->VDisplay = kmode->vdisplay; 182de2362d3Smrg mode->VSyncStart = kmode->vsync_start; 183de2362d3Smrg mode->VSyncEnd = kmode->vsync_end; 184de2362d3Smrg mode->VTotal = kmode->vtotal; 185de2362d3Smrg mode->VScan = kmode->vscan; 186de2362d3Smrg 187de2362d3Smrg mode->Flags = kmode->flags; //& FLAG_BITS; 188de2362d3Smrg mode->name = strdup(kmode->name); 189de2362d3Smrg 190de2362d3Smrg if (kmode->type & DRM_MODE_TYPE_DRIVER) 191de2362d3Smrg mode->type = M_T_DRIVER; 192de2362d3Smrg if (kmode->type & DRM_MODE_TYPE_PREFERRED) 193de2362d3Smrg mode->type |= M_T_PREFERRED; 194de2362d3Smrg xf86SetModeCrtc (mode, scrn->adjustFlags); 195de2362d3Smrg} 196de2362d3Smrg 197de2362d3Smrgstatic void 198de2362d3Smrgdrmmode_ConvertToKMode(ScrnInfoPtr scrn, 199de2362d3Smrg drmModeModeInfo *kmode, 200de2362d3Smrg DisplayModePtr mode) 201de2362d3Smrg{ 202de2362d3Smrg memset(kmode, 0, sizeof(*kmode)); 203de2362d3Smrg 204de2362d3Smrg kmode->clock = mode->Clock; 205de2362d3Smrg kmode->hdisplay = mode->HDisplay; 206de2362d3Smrg kmode->hsync_start = mode->HSyncStart; 207de2362d3Smrg kmode->hsync_end = mode->HSyncEnd; 208de2362d3Smrg kmode->htotal = mode->HTotal; 209de2362d3Smrg kmode->hskew = mode->HSkew; 210de2362d3Smrg 211de2362d3Smrg kmode->vdisplay = mode->VDisplay; 212de2362d3Smrg kmode->vsync_start = mode->VSyncStart; 213de2362d3Smrg kmode->vsync_end = mode->VSyncEnd; 214de2362d3Smrg kmode->vtotal = mode->VTotal; 215de2362d3Smrg kmode->vscan = mode->VScan; 216de2362d3Smrg 217de2362d3Smrg kmode->flags = mode->Flags; //& FLAG_BITS; 218de2362d3Smrg if (mode->name) 219de2362d3Smrg strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); 220de2362d3Smrg kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0; 221de2362d3Smrg 222de2362d3Smrg} 223de2362d3Smrg 224de2362d3Smrg/* 225de2362d3Smrg * Retrieves present time in microseconds that is compatible 226de2362d3Smrg * with units used by vblank timestamps. Depending on the kernel 227de2362d3Smrg * version and DRM kernel module configuration, the vblank 228de2362d3Smrg * timestamp can either be in real time or monotonic time 229de2362d3Smrg */ 230de2362d3Smrgint drmmode_get_current_ust(int drm_fd, CARD64 *ust) 231de2362d3Smrg{ 232de2362d3Smrg uint64_t cap_value; 233de2362d3Smrg int ret; 234de2362d3Smrg struct timespec now; 235de2362d3Smrg 236de2362d3Smrg ret = drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap_value); 237de2362d3Smrg if (ret || !cap_value) 238de2362d3Smrg /* old kernel or drm_timestamp_monotonic turned off */ 239de2362d3Smrg ret = clock_gettime(CLOCK_REALTIME, &now); 240de2362d3Smrg else 241de2362d3Smrg ret = clock_gettime(CLOCK_MONOTONIC, &now); 242de2362d3Smrg if (ret) 243de2362d3Smrg return ret; 244de2362d3Smrg *ust = ((CARD64)now.tv_sec * 1000000) + ((CARD64)now.tv_nsec / 1000); 245de2362d3Smrg return 0; 246de2362d3Smrg} 247de2362d3Smrg 248de2362d3Smrgstatic void 249de2362d3Smrgdrmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode) 250de2362d3Smrg{ 251de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 252de2362d3Smrg ScrnInfoPtr scrn = crtc->scrn; 253de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 254de2362d3Smrg CARD64 ust; 255de2362d3Smrg int ret; 256de2362d3Smrg 257de2362d3Smrg if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) { 258de2362d3Smrg drmVBlank vbl; 259de2362d3Smrg 260de2362d3Smrg /* 261de2362d3Smrg * On->Off transition: record the last vblank time, 262de2362d3Smrg * sequence number and frame period. 263de2362d3Smrg */ 264de2362d3Smrg vbl.request.type = DRM_VBLANK_RELATIVE; 265de2362d3Smrg vbl.request.type |= radeon_populate_vbl_request_type(crtc); 266de2362d3Smrg vbl.request.sequence = 0; 267de2362d3Smrg ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 268de2362d3Smrg if (ret) 269de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 270de2362d3Smrg "%s cannot get last vblank counter\n", 271de2362d3Smrg __func__); 272de2362d3Smrg else { 273de2362d3Smrg CARD64 seq = (CARD64)vbl.reply.sequence; 274de2362d3Smrg CARD64 nominal_frame_rate, pix_in_frame; 275de2362d3Smrg 276de2362d3Smrg ust = ((CARD64)vbl.reply.tval_sec * 1000000) + 277de2362d3Smrg vbl.reply.tval_usec; 278de2362d3Smrg drmmode_crtc->dpms_last_ust = ust; 279de2362d3Smrg drmmode_crtc->dpms_last_seq = seq; 280de2362d3Smrg nominal_frame_rate = crtc->mode.Clock; 281de2362d3Smrg nominal_frame_rate *= 1000; 282de2362d3Smrg pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal; 283de2362d3Smrg if (nominal_frame_rate == 0 || pix_in_frame == 0) 284de2362d3Smrg nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE; 285de2362d3Smrg else 286de2362d3Smrg nominal_frame_rate /= pix_in_frame; 287de2362d3Smrg drmmode_crtc->dpms_last_fps = nominal_frame_rate; 288de2362d3Smrg } 289de2362d3Smrg } else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) { 290de2362d3Smrg /* 291de2362d3Smrg * Off->On transition: calculate and accumulate the 292de2362d3Smrg * number of interpolated vblanks while we were in Off state 293de2362d3Smrg */ 294de2362d3Smrg ret = drmmode_get_current_ust(info->dri2.drm_fd, &ust); 295de2362d3Smrg if (ret) 296de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 297de2362d3Smrg "%s cannot get current time\n", __func__); 298de2362d3Smrg else if (drmmode_crtc->dpms_last_ust) { 299de2362d3Smrg CARD64 time_elapsed, delta_seq; 300de2362d3Smrg time_elapsed = ust - drmmode_crtc->dpms_last_ust; 301de2362d3Smrg delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps; 302de2362d3Smrg delta_seq /= 1000000; 303de2362d3Smrg drmmode_crtc->interpolated_vblanks += delta_seq; 304de2362d3Smrg 305de2362d3Smrg } 306de2362d3Smrg } 307de2362d3Smrg drmmode_crtc->dpms_mode = mode; 308de2362d3Smrg} 309de2362d3Smrg 310de2362d3Smrgstatic void 311de2362d3Smrgdrmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) 312de2362d3Smrg{ 313de2362d3Smrg /* Nothing to do. drmmode_do_crtc_dpms() is called as appropriate */ 314de2362d3Smrg} 315de2362d3Smrg 316de2362d3Smrgstatic PixmapPtr 317de2362d3Smrgcreate_pixmap_for_fbcon(drmmode_ptr drmmode, 318de2362d3Smrg ScrnInfoPtr pScrn, int fbcon_id) 319de2362d3Smrg{ 320de2362d3Smrg PixmapPtr pixmap = NULL; 321de2362d3Smrg struct radeon_bo *bo; 322de2362d3Smrg drmModeFBPtr fbcon; 323de2362d3Smrg struct drm_gem_flink flink; 324de2362d3Smrg 325de2362d3Smrg fbcon = drmModeGetFB(drmmode->fd, fbcon_id); 326de2362d3Smrg if (fbcon == NULL) 327de2362d3Smrg return NULL; 328de2362d3Smrg 329de2362d3Smrg if (fbcon->depth != pScrn->depth || 330de2362d3Smrg fbcon->width != pScrn->virtualX || 331de2362d3Smrg fbcon->height != pScrn->virtualY) 332de2362d3Smrg goto out_free_fb; 333de2362d3Smrg 334de2362d3Smrg flink.handle = fbcon->handle; 335de2362d3Smrg if (ioctl(drmmode->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) { 336de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 337de2362d3Smrg "Couldn't flink fbcon handle\n"); 338de2362d3Smrg goto out_free_fb; 339de2362d3Smrg } 340de2362d3Smrg 341de2362d3Smrg bo = radeon_bo_open(drmmode->bufmgr, flink.name, 0, 0, 0, 0); 342de2362d3Smrg if (bo == NULL) { 343de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 344de2362d3Smrg "Couldn't allocate bo for fbcon handle\n"); 345de2362d3Smrg goto out_free_fb; 346de2362d3Smrg } 347de2362d3Smrg 348de2362d3Smrg pixmap = drmmode_create_bo_pixmap(pScrn, fbcon->width, fbcon->height, 349de2362d3Smrg fbcon->depth, fbcon->bpp, 350de2362d3Smrg fbcon->pitch, 0, bo, NULL); 351de2362d3Smrg radeon_bo_unref(bo); 352de2362d3Smrgout_free_fb: 353de2362d3Smrg drmModeFreeFB(fbcon); 354de2362d3Smrg return pixmap; 355de2362d3Smrg} 356de2362d3Smrg 357de2362d3Smrgvoid drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 358de2362d3Smrg{ 359de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 360de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 361de2362d3Smrg PixmapPtr src, dst; 362de2362d3Smrg ScreenPtr pScreen = pScrn->pScreen; 363de2362d3Smrg int fbcon_id = 0; 364de2362d3Smrg int i; 365de2362d3Smrg int pitch; 366de2362d3Smrg uint32_t tiling_flags = 0; 367de2362d3Smrg Bool ret; 368de2362d3Smrg 369de2362d3Smrg if (info->accelOn == FALSE || info->use_glamor) 370de2362d3Smrg goto fallback; 371de2362d3Smrg 372de2362d3Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 373de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private; 374de2362d3Smrg 375de2362d3Smrg if (drmmode_crtc->mode_crtc->buffer_id) 376de2362d3Smrg fbcon_id = drmmode_crtc->mode_crtc->buffer_id; 377de2362d3Smrg } 378de2362d3Smrg 379de2362d3Smrg if (!fbcon_id) 380de2362d3Smrg goto fallback; 381de2362d3Smrg 382de2362d3Smrg if (fbcon_id == drmmode->fb_id) { 383de2362d3Smrg /* in some rare case there might be no fbcon and we might already 384de2362d3Smrg * be the one with the current fb to avoid a false deadlck in 385de2362d3Smrg * kernel ttm code just do nothing as anyway there is nothing 386de2362d3Smrg * to do 387de2362d3Smrg */ 388de2362d3Smrg return; 389de2362d3Smrg } 390de2362d3Smrg 391de2362d3Smrg src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id); 392de2362d3Smrg if (!src) 393de2362d3Smrg goto fallback; 394de2362d3Smrg 395de2362d3Smrg if (info->allowColorTiling) { 396de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 397de2362d3Smrg if (info->allowColorTiling2D) { 398de2362d3Smrg tiling_flags |= RADEON_TILING_MACRO; 399de2362d3Smrg } else { 400de2362d3Smrg tiling_flags |= RADEON_TILING_MICRO; 401de2362d3Smrg } 402de2362d3Smrg } else 403de2362d3Smrg tiling_flags |= RADEON_TILING_MACRO; 404de2362d3Smrg } 405de2362d3Smrg 406de2362d3Smrg pitch = RADEON_ALIGN(pScrn->displayWidth, 407de2362d3Smrg drmmode_get_pitch_align(pScrn, info->pixel_bytes, tiling_flags)) * 408de2362d3Smrg info->pixel_bytes; 409de2362d3Smrg 410de2362d3Smrg dst = drmmode_create_bo_pixmap(pScrn, pScrn->virtualX, 411de2362d3Smrg pScrn->virtualY, pScrn->depth, 412de2362d3Smrg pScrn->bitsPerPixel, pitch, 413de2362d3Smrg tiling_flags, info->front_bo, &info->front_surface); 414de2362d3Smrg if (!dst) 415de2362d3Smrg goto out_free_src; 416de2362d3Smrg 417de2362d3Smrg ret = info->accel_state->exa->PrepareCopy (src, dst, 418de2362d3Smrg -1, -1, GXcopy, FB_ALLONES); 419de2362d3Smrg if (!ret) 420de2362d3Smrg goto out_free_src; 421de2362d3Smrg info->accel_state->exa->Copy (dst, 0, 0, 0, 0, 422de2362d3Smrg pScrn->virtualX, pScrn->virtualY); 423de2362d3Smrg info->accel_state->exa->DoneCopy (dst); 424de2362d3Smrg radeon_cs_flush_indirect(pScrn); 425de2362d3Smrg 426de2362d3Smrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 10 427de2362d3Smrg pScreen->canDoBGNoneRoot = TRUE; 428de2362d3Smrg#endif 429de2362d3Smrg drmmode_destroy_bo_pixmap(dst); 430de2362d3Smrg out_free_src: 431de2362d3Smrg drmmode_destroy_bo_pixmap(src); 432de2362d3Smrg return; 433de2362d3Smrg 434de2362d3Smrgfallback: 435de2362d3Smrg /* map and memset the bo */ 436de2362d3Smrg if (radeon_bo_map(info->front_bo, 1)) 437de2362d3Smrg return; 438de2362d3Smrg 439de2362d3Smrg memset(info->front_bo->ptr, 0x00, info->front_bo->size); 440de2362d3Smrg radeon_bo_unmap(info->front_bo); 441de2362d3Smrg} 442de2362d3Smrg 443de2362d3Smrgstatic Bool 444de2362d3Smrgdrmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 445de2362d3Smrg Rotation rotation, int x, int y) 446de2362d3Smrg{ 447de2362d3Smrg ScrnInfoPtr pScrn = crtc->scrn; 448de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 449de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 450de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 451de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 452de2362d3Smrg int saved_x, saved_y; 453de2362d3Smrg Rotation saved_rotation; 454de2362d3Smrg DisplayModeRec saved_mode; 455de2362d3Smrg uint32_t *output_ids; 456de2362d3Smrg int output_count = 0; 457de2362d3Smrg Bool ret = TRUE; 458de2362d3Smrg int i; 459de2362d3Smrg int fb_id; 460de2362d3Smrg drmModeModeInfo kmode; 461de2362d3Smrg int pitch; 462de2362d3Smrg uint32_t tiling_flags = 0; 463de2362d3Smrg int height; 464de2362d3Smrg 465de2362d3Smrg if (info->allowColorTiling) { 466de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) 467de2362d3Smrg tiling_flags |= RADEON_TILING_MICRO; 468de2362d3Smrg else 469de2362d3Smrg tiling_flags |= RADEON_TILING_MACRO; 470de2362d3Smrg } 471de2362d3Smrg 472de2362d3Smrg pitch = RADEON_ALIGN(pScrn->displayWidth, drmmode_get_pitch_align(pScrn, info->pixel_bytes, tiling_flags)) * 473de2362d3Smrg info->pixel_bytes; 474de2362d3Smrg height = RADEON_ALIGN(pScrn->virtualY, drmmode_get_height_align(pScrn, tiling_flags)); 475de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 476de2362d3Smrg pitch = info->front_surface.level[0].pitch_bytes; 477de2362d3Smrg } 478de2362d3Smrg 479de2362d3Smrg if (drmmode->fb_id == 0) { 480de2362d3Smrg ret = drmModeAddFB(drmmode->fd, 481de2362d3Smrg pScrn->virtualX, height, 482de2362d3Smrg pScrn->depth, pScrn->bitsPerPixel, 483de2362d3Smrg pitch, 484de2362d3Smrg info->front_bo->handle, 485de2362d3Smrg &drmmode->fb_id); 486de2362d3Smrg if (ret < 0) { 487de2362d3Smrg ErrorF("failed to add fb\n"); 488de2362d3Smrg return FALSE; 489de2362d3Smrg } 490de2362d3Smrg } 491de2362d3Smrg 492de2362d3Smrg saved_mode = crtc->mode; 493de2362d3Smrg saved_x = crtc->x; 494de2362d3Smrg saved_y = crtc->y; 495de2362d3Smrg saved_rotation = crtc->rotation; 496de2362d3Smrg 497de2362d3Smrg if (mode) { 498de2362d3Smrg crtc->mode = *mode; 499de2362d3Smrg crtc->x = x; 500de2362d3Smrg crtc->y = y; 501de2362d3Smrg crtc->rotation = rotation; 502de2362d3Smrg crtc->transformPresent = FALSE; 503de2362d3Smrg } 504de2362d3Smrg 505de2362d3Smrg output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); 506de2362d3Smrg if (!output_ids) { 507de2362d3Smrg ret = FALSE; 508de2362d3Smrg goto done; 509de2362d3Smrg } 510de2362d3Smrg 511de2362d3Smrg if (mode) { 512de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 513de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 514de2362d3Smrg drmmode_output_private_ptr drmmode_output; 515de2362d3Smrg 516de2362d3Smrg if (output->crtc != crtc) 517de2362d3Smrg continue; 518de2362d3Smrg 519de2362d3Smrg drmmode_output = output->driver_private; 520de2362d3Smrg output_ids[output_count] = drmmode_output->mode_output->connector_id; 521de2362d3Smrg output_count++; 522de2362d3Smrg } 523de2362d3Smrg 524de2362d3Smrg if (!xf86CrtcRotate(crtc)) { 525de2362d3Smrg goto done; 526de2362d3Smrg } 527de2362d3Smrg crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, 528de2362d3Smrg crtc->gamma_blue, crtc->gamma_size); 529de2362d3Smrg 530de2362d3Smrg drmmode_ConvertToKMode(crtc->scrn, &kmode, mode); 531de2362d3Smrg 532de2362d3Smrg fb_id = drmmode->fb_id; 533de2362d3Smrg#ifdef RADEON_PIXMAP_SHARING 534de2362d3Smrg if (crtc->randr_crtc && crtc->randr_crtc->scanout_pixmap) { 535de2362d3Smrg x = drmmode_crtc->scanout_pixmap_x; 536de2362d3Smrg y = 0; 537de2362d3Smrg } else 538de2362d3Smrg#endif 539de2362d3Smrg if (drmmode_crtc->rotate_fb_id) { 540de2362d3Smrg fb_id = drmmode_crtc->rotate_fb_id; 541de2362d3Smrg x = y = 0; 542de2362d3Smrg } 543de2362d3Smrg ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 544de2362d3Smrg fb_id, x, y, output_ids, output_count, &kmode); 545de2362d3Smrg if (ret) 546de2362d3Smrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 547de2362d3Smrg "failed to set mode: %s", strerror(-ret)); 548de2362d3Smrg else 549de2362d3Smrg ret = TRUE; 550de2362d3Smrg 551de2362d3Smrg if (crtc->scrn->pScreen) 552de2362d3Smrg xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen); 553de2362d3Smrg /* go through all the outputs and force DPMS them back on? */ 554de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 555de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 556de2362d3Smrg 557de2362d3Smrg if (output->crtc != crtc) 558de2362d3Smrg continue; 559de2362d3Smrg 560de2362d3Smrg output->funcs->dpms(output, DPMSModeOn); 561de2362d3Smrg } 562de2362d3Smrg } 563de2362d3Smrg 564de2362d3Smrg if (pScrn->pScreen && 565de2362d3Smrg !xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) 566de2362d3Smrg xf86_reload_cursors(pScrn->pScreen); 567de2362d3Smrg 568de2362d3Smrgdone: 569de2362d3Smrg if (!ret) { 570de2362d3Smrg crtc->x = saved_x; 571de2362d3Smrg crtc->y = saved_y; 572de2362d3Smrg crtc->rotation = saved_rotation; 573de2362d3Smrg crtc->mode = saved_mode; 574de2362d3Smrg } 575de2362d3Smrg#if defined(XF86_CRTC_VERSION) && XF86_CRTC_VERSION >= 3 576de2362d3Smrg else 577de2362d3Smrg crtc->active = TRUE; 578de2362d3Smrg#endif 579de2362d3Smrg 580de2362d3Smrg return ret; 581de2362d3Smrg} 582de2362d3Smrg 583de2362d3Smrgstatic void 584de2362d3Smrgdrmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg) 585de2362d3Smrg{ 586de2362d3Smrg 587de2362d3Smrg} 588de2362d3Smrg 589de2362d3Smrgstatic void 590de2362d3Smrgdrmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y) 591de2362d3Smrg{ 592de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 593de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 594de2362d3Smrg 595de2362d3Smrg drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); 596de2362d3Smrg} 597de2362d3Smrg 598de2362d3Smrgstatic void 599de2362d3Smrgdrmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image) 600de2362d3Smrg{ 601de2362d3Smrg ScrnInfoPtr pScrn = crtc->scrn; 602de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 603de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 604de2362d3Smrg int i; 605de2362d3Smrg uint32_t *ptr; 606de2362d3Smrg uint32_t cursor_size = info->cursor_w * info->cursor_h; 607de2362d3Smrg 608de2362d3Smrg /* cursor should be mapped already */ 609de2362d3Smrg ptr = (uint32_t *)(drmmode_crtc->cursor_bo->ptr); 610de2362d3Smrg 611de2362d3Smrg for (i = 0; i < cursor_size; i++) 612de2362d3Smrg ptr[i] = cpu_to_le32(image[i]); 613de2362d3Smrg} 614de2362d3Smrg 615de2362d3Smrg 616de2362d3Smrgstatic void 617de2362d3Smrgdrmmode_hide_cursor (xf86CrtcPtr crtc) 618de2362d3Smrg{ 619de2362d3Smrg ScrnInfoPtr pScrn = crtc->scrn; 620de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 621de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 622de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 623de2362d3Smrg 624de2362d3Smrg drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 625de2362d3Smrg info->cursor_w, info->cursor_h); 626de2362d3Smrg 627de2362d3Smrg} 628de2362d3Smrg 629de2362d3Smrgstatic void 630de2362d3Smrgdrmmode_show_cursor (xf86CrtcPtr crtc) 631de2362d3Smrg{ 632de2362d3Smrg ScrnInfoPtr pScrn = crtc->scrn; 633de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 634de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 635de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 636de2362d3Smrg uint32_t handle = drmmode_crtc->cursor_bo->handle; 637de2362d3Smrg 638de2362d3Smrg drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, handle, 639de2362d3Smrg info->cursor_w, info->cursor_h); 640de2362d3Smrg} 641de2362d3Smrg 642de2362d3Smrgstatic void * 643de2362d3Smrgdrmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 644de2362d3Smrg{ 645de2362d3Smrg ScrnInfoPtr pScrn = crtc->scrn; 646de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 647de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 648de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 649de2362d3Smrg int size; 650de2362d3Smrg struct radeon_bo *rotate_bo; 651de2362d3Smrg int ret; 652de2362d3Smrg unsigned long rotate_pitch; 653de2362d3Smrg int base_align; 654de2362d3Smrg 655de2362d3Smrg /* rotation requires acceleration */ 656de2362d3Smrg if (info->r600_shadow_fb) { 657de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 658de2362d3Smrg "Rotation requires acceleration!\n"); 659de2362d3Smrg return NULL; 660de2362d3Smrg } 661de2362d3Smrg 662de2362d3Smrg rotate_pitch = 663de2362d3Smrg RADEON_ALIGN(width, drmmode_get_pitch_align(crtc->scrn, drmmode->cpp, 0)) * drmmode->cpp; 664de2362d3Smrg height = RADEON_ALIGN(height, drmmode_get_height_align(crtc->scrn, 0)); 665de2362d3Smrg base_align = drmmode_get_base_align(crtc->scrn, drmmode->cpp, 0); 666de2362d3Smrg size = RADEON_ALIGN(rotate_pitch * height, RADEON_GPU_PAGE_SIZE); 667de2362d3Smrg 668de2362d3Smrg rotate_bo = radeon_bo_open(drmmode->bufmgr, 0, size, base_align, RADEON_GEM_DOMAIN_VRAM, 0); 669de2362d3Smrg if (rotate_bo == NULL) 670de2362d3Smrg return NULL; 671de2362d3Smrg 672de2362d3Smrg radeon_bo_map(rotate_bo, 1); 673de2362d3Smrg 674de2362d3Smrg ret = drmModeAddFB(drmmode->fd, width, height, crtc->scrn->depth, 675de2362d3Smrg crtc->scrn->bitsPerPixel, rotate_pitch, 676de2362d3Smrg rotate_bo->handle, 677de2362d3Smrg &drmmode_crtc->rotate_fb_id); 678de2362d3Smrg if (ret) { 679de2362d3Smrg ErrorF("failed to add rotate fb\n"); 680de2362d3Smrg } 681de2362d3Smrg 682de2362d3Smrg drmmode_crtc->rotate_bo = rotate_bo; 683de2362d3Smrg return drmmode_crtc->rotate_bo->ptr; 684de2362d3Smrg} 685de2362d3Smrg 686de2362d3Smrgstatic PixmapPtr 687de2362d3Smrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 688de2362d3Smrg{ 689de2362d3Smrg ScrnInfoPtr pScrn = crtc->scrn; 690de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 691de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 692de2362d3Smrg unsigned long rotate_pitch; 693de2362d3Smrg PixmapPtr rotate_pixmap; 694de2362d3Smrg 695de2362d3Smrg if (!data) 696de2362d3Smrg data = drmmode_crtc_shadow_allocate (crtc, width, height); 697de2362d3Smrg 698de2362d3Smrg rotate_pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, drmmode->cpp, 0)) * drmmode->cpp; 699de2362d3Smrg 700de2362d3Smrg rotate_pixmap = drmmode_create_bo_pixmap(pScrn, 701de2362d3Smrg width, height, 702de2362d3Smrg pScrn->depth, 703de2362d3Smrg pScrn->bitsPerPixel, 704de2362d3Smrg rotate_pitch, 705de2362d3Smrg 0, drmmode_crtc->rotate_bo, NULL); 706de2362d3Smrg if (rotate_pixmap == NULL) { 707de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 708de2362d3Smrg "Couldn't allocate shadow pixmap for rotated CRTC\n"); 709de2362d3Smrg } 710de2362d3Smrg return rotate_pixmap; 711de2362d3Smrg 712de2362d3Smrg} 713de2362d3Smrg 714de2362d3Smrgstatic void 715de2362d3Smrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) 716de2362d3Smrg{ 717de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 718de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 719de2362d3Smrg 720de2362d3Smrg if (rotate_pixmap) 721de2362d3Smrg drmmode_destroy_bo_pixmap(rotate_pixmap); 722de2362d3Smrg 723de2362d3Smrg if (data) { 724de2362d3Smrg drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id); 725de2362d3Smrg drmmode_crtc->rotate_fb_id = 0; 726de2362d3Smrg radeon_bo_unmap(drmmode_crtc->rotate_bo); 727de2362d3Smrg radeon_bo_unref(drmmode_crtc->rotate_bo); 728de2362d3Smrg drmmode_crtc->rotate_bo = NULL; 729de2362d3Smrg } 730de2362d3Smrg 731de2362d3Smrg} 732de2362d3Smrg 733de2362d3Smrgstatic void 734de2362d3Smrgdrmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 735de2362d3Smrg uint16_t *blue, int size) 736de2362d3Smrg{ 737de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 738de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 739de2362d3Smrg 740de2362d3Smrg drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 741de2362d3Smrg size, red, green, blue); 742de2362d3Smrg} 743de2362d3Smrg 744de2362d3Smrg#ifdef RADEON_PIXMAP_SHARING 745de2362d3Smrgstatic Bool 746de2362d3Smrgdrmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) 747de2362d3Smrg{ 748de2362d3Smrg ScreenPtr screen = xf86ScrnToScreen(crtc->scrn); 749de2362d3Smrg PixmapPtr screenpix = screen->GetScreenPixmap(screen); 750de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 751de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 752de2362d3Smrg int c, total_width = 0, max_height = 0, this_x = 0; 753de2362d3Smrg 754de2362d3Smrg if (!ppix) { 755de2362d3Smrg if (crtc->randr_crtc->scanout_pixmap) 756de2362d3Smrg PixmapStopDirtyTracking(crtc->randr_crtc->scanout_pixmap, screenpix); 757de2362d3Smrg drmmode_crtc->scanout_pixmap_x = 0; 758de2362d3Smrg return TRUE; 759de2362d3Smrg } 760de2362d3Smrg 761de2362d3Smrg /* iterate over all the attached crtcs - 762de2362d3Smrg work out bounding box */ 763de2362d3Smrg for (c = 0; c < xf86_config->num_crtc; c++) { 764de2362d3Smrg xf86CrtcPtr iter = xf86_config->crtc[c]; 765de2362d3Smrg if (!iter->enabled && iter != crtc) 766de2362d3Smrg continue; 767de2362d3Smrg if (iter == crtc) { 768de2362d3Smrg this_x = total_width; 769de2362d3Smrg total_width += ppix->drawable.width; 770de2362d3Smrg if (max_height < ppix->drawable.height) 771de2362d3Smrg max_height = ppix->drawable.height; 772de2362d3Smrg } else { 773de2362d3Smrg total_width += iter->mode.HDisplay; 774de2362d3Smrg if (max_height < iter->mode.VDisplay) 775de2362d3Smrg max_height = iter->mode.VDisplay; 776de2362d3Smrg } 777de2362d3Smrg#ifndef HAS_DIRTYTRACKING2 778de2362d3Smrg if (iter != crtc) { 779de2362d3Smrg ErrorF("Cannot do multiple crtcs without X server dirty tracking 2 interface\n"); 780de2362d3Smrg return FALSE; 781de2362d3Smrg } 782de2362d3Smrg#endif 783de2362d3Smrg } 784de2362d3Smrg 785de2362d3Smrg if (total_width != screenpix->drawable.width || 786de2362d3Smrg max_height != screenpix->drawable.height) { 787de2362d3Smrg Bool ret; 788de2362d3Smrg ret = drmmode_xf86crtc_resize(crtc->scrn, total_width, max_height); 789de2362d3Smrg if (ret == FALSE) 790de2362d3Smrg return FALSE; 791de2362d3Smrg 792de2362d3Smrg screenpix = screen->GetScreenPixmap(screen); 793de2362d3Smrg screen->width = screenpix->drawable.width = total_width; 794de2362d3Smrg screen->height = screenpix->drawable.height = max_height; 795de2362d3Smrg } 796de2362d3Smrg drmmode_crtc->scanout_pixmap_x = this_x; 797de2362d3Smrg#ifdef HAS_DIRTYTRACKING2 798de2362d3Smrg PixmapStartDirtyTracking2(ppix, screenpix, 0, 0, this_x, 0); 799de2362d3Smrg#else 800de2362d3Smrg PixmapStartDirtyTracking(ppix, screenpix, 0, 0); 801de2362d3Smrg#endif 802de2362d3Smrg return TRUE; 803de2362d3Smrg} 804de2362d3Smrg#endif 805de2362d3Smrg 806de2362d3Smrgstatic const xf86CrtcFuncsRec drmmode_crtc_funcs = { 807de2362d3Smrg .dpms = drmmode_crtc_dpms, 808de2362d3Smrg .set_mode_major = drmmode_set_mode_major, 809de2362d3Smrg .set_cursor_colors = drmmode_set_cursor_colors, 810de2362d3Smrg .set_cursor_position = drmmode_set_cursor_position, 811de2362d3Smrg .show_cursor = drmmode_show_cursor, 812de2362d3Smrg .hide_cursor = drmmode_hide_cursor, 813de2362d3Smrg .load_cursor_argb = drmmode_load_cursor_argb, 814de2362d3Smrg 815de2362d3Smrg .gamma_set = drmmode_crtc_gamma_set, 816de2362d3Smrg .shadow_create = drmmode_crtc_shadow_create, 817de2362d3Smrg .shadow_allocate = drmmode_crtc_shadow_allocate, 818de2362d3Smrg .shadow_destroy = drmmode_crtc_shadow_destroy, 819de2362d3Smrg .destroy = NULL, /* XXX */ 820de2362d3Smrg#ifdef RADEON_PIXMAP_SHARING 821de2362d3Smrg .set_scanout_pixmap = drmmode_set_scanout_pixmap, 822de2362d3Smrg#endif 823de2362d3Smrg}; 824de2362d3Smrg 825de2362d3Smrgint drmmode_get_crtc_id(xf86CrtcPtr crtc) 826de2362d3Smrg{ 827de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 828de2362d3Smrg return drmmode_crtc->hw_id; 829de2362d3Smrg} 830de2362d3Smrg 831de2362d3Smrgvoid drmmode_crtc_hw_id(xf86CrtcPtr crtc) 832de2362d3Smrg{ 833de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 834de2362d3Smrg ScrnInfoPtr pScrn = crtc->scrn; 835de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 836de2362d3Smrg struct drm_radeon_info ginfo; 837de2362d3Smrg int r; 838de2362d3Smrg uint32_t tmp; 839de2362d3Smrg 840de2362d3Smrg memset(&ginfo, 0, sizeof(ginfo)); 841de2362d3Smrg ginfo.request = 0x4; 842de2362d3Smrg tmp = drmmode_crtc->mode_crtc->crtc_id; 843de2362d3Smrg ginfo.value = (uintptr_t)&tmp; 844de2362d3Smrg r = drmCommandWriteRead(info->dri2.drm_fd, DRM_RADEON_INFO, &ginfo, sizeof(ginfo)); 845de2362d3Smrg if (r) { 846de2362d3Smrg drmmode_crtc->hw_id = -1; 847de2362d3Smrg return; 848de2362d3Smrg } 849de2362d3Smrg drmmode_crtc->hw_id = tmp; 850de2362d3Smrg} 851de2362d3Smrg 852de2362d3Smrgstatic void 853de2362d3Smrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num) 854de2362d3Smrg{ 855de2362d3Smrg xf86CrtcPtr crtc; 856de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc; 857de2362d3Smrg 858de2362d3Smrg crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs); 859de2362d3Smrg if (crtc == NULL) 860de2362d3Smrg return; 861de2362d3Smrg 862de2362d3Smrg drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); 863de2362d3Smrg drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, drmmode->mode_res->crtcs[num]); 864de2362d3Smrg drmmode_crtc->drmmode = drmmode; 865de2362d3Smrg crtc->driver_private = drmmode_crtc; 866de2362d3Smrg drmmode_crtc_hw_id(crtc); 867de2362d3Smrg 868de2362d3Smrg return; 869de2362d3Smrg} 870de2362d3Smrg 871de2362d3Smrgstatic xf86OutputStatus 872de2362d3Smrgdrmmode_output_detect(xf86OutputPtr output) 873de2362d3Smrg{ 874de2362d3Smrg /* go to the hw and retrieve a new output struct */ 875de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 876de2362d3Smrg drmmode_ptr drmmode = drmmode_output->drmmode; 877de2362d3Smrg xf86OutputStatus status; 878de2362d3Smrg drmModeFreeConnector(drmmode_output->mode_output); 879de2362d3Smrg 880de2362d3Smrg drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id); 881de2362d3Smrg if (!drmmode_output->mode_output) 882de2362d3Smrg return XF86OutputStatusDisconnected; 883de2362d3Smrg 884de2362d3Smrg switch (drmmode_output->mode_output->connection) { 885de2362d3Smrg case DRM_MODE_CONNECTED: 886de2362d3Smrg status = XF86OutputStatusConnected; 887de2362d3Smrg break; 888de2362d3Smrg case DRM_MODE_DISCONNECTED: 889de2362d3Smrg status = XF86OutputStatusDisconnected; 890de2362d3Smrg break; 891de2362d3Smrg default: 892de2362d3Smrg case DRM_MODE_UNKNOWNCONNECTION: 893de2362d3Smrg status = XF86OutputStatusUnknown; 894de2362d3Smrg break; 895de2362d3Smrg } 896de2362d3Smrg return status; 897de2362d3Smrg} 898de2362d3Smrg 899de2362d3Smrgstatic Bool 900de2362d3Smrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) 901de2362d3Smrg{ 902de2362d3Smrg return MODE_OK; 903de2362d3Smrg} 904de2362d3Smrg 905de2362d3Smrgstatic DisplayModePtr 906de2362d3Smrgdrmmode_output_get_modes(xf86OutputPtr output) 907de2362d3Smrg{ 908de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 909de2362d3Smrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 910de2362d3Smrg drmmode_ptr drmmode = drmmode_output->drmmode; 911de2362d3Smrg int i; 912de2362d3Smrg DisplayModePtr Modes = NULL, Mode; 913de2362d3Smrg drmModePropertyPtr props; 914de2362d3Smrg xf86MonPtr mon = NULL; 915de2362d3Smrg 916de2362d3Smrg if (!koutput) 917de2362d3Smrg return NULL; 918de2362d3Smrg 919de2362d3Smrg /* look for an EDID property */ 920de2362d3Smrg for (i = 0; i < koutput->count_props; i++) { 921de2362d3Smrg props = drmModeGetProperty(drmmode->fd, koutput->props[i]); 922de2362d3Smrg if (props && (props->flags & DRM_MODE_PROP_BLOB)) { 923de2362d3Smrg if (!strcmp(props->name, "EDID")) { 924de2362d3Smrg if (drmmode_output->edid_blob) 925de2362d3Smrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 926de2362d3Smrg drmmode_output->edid_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]); 927de2362d3Smrg } 928de2362d3Smrg } 929de2362d3Smrg if (props) 930de2362d3Smrg drmModeFreeProperty(props); 931de2362d3Smrg } 932de2362d3Smrg 933de2362d3Smrg if (drmmode_output->edid_blob) { 934de2362d3Smrg mon = xf86InterpretEDID(output->scrn->scrnIndex, 935de2362d3Smrg drmmode_output->edid_blob->data); 936de2362d3Smrg if (mon && drmmode_output->edid_blob->length > 128) 937de2362d3Smrg mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 938de2362d3Smrg } 939de2362d3Smrg xf86OutputSetEDID(output, mon); 940de2362d3Smrg 941de2362d3Smrg /* modes should already be available */ 942de2362d3Smrg for (i = 0; i < koutput->count_modes; i++) { 943de2362d3Smrg Mode = xnfalloc(sizeof(DisplayModeRec)); 944de2362d3Smrg 945de2362d3Smrg drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode); 946de2362d3Smrg Modes = xf86ModesAdd(Modes, Mode); 947de2362d3Smrg 948de2362d3Smrg } 949de2362d3Smrg return Modes; 950de2362d3Smrg} 951de2362d3Smrg 952de2362d3Smrgstatic void 953de2362d3Smrgdrmmode_output_destroy(xf86OutputPtr output) 954de2362d3Smrg{ 955de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 956de2362d3Smrg int i; 957de2362d3Smrg 958de2362d3Smrg if (drmmode_output->edid_blob) 959de2362d3Smrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 960de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 961de2362d3Smrg drmModeFreeProperty(drmmode_output->props[i].mode_prop); 962de2362d3Smrg free(drmmode_output->props[i].atoms); 963de2362d3Smrg } 964de2362d3Smrg for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) { 965de2362d3Smrg drmModeFreeEncoder(drmmode_output->mode_encoders[i]); 966de2362d3Smrg } 967de2362d3Smrg free(drmmode_output->mode_encoders); 968de2362d3Smrg free(drmmode_output->props); 969de2362d3Smrg drmModeFreeConnector(drmmode_output->mode_output); 970de2362d3Smrg free(drmmode_output); 971de2362d3Smrg output->driver_private = NULL; 972de2362d3Smrg} 973de2362d3Smrg 974de2362d3Smrgstatic void 975de2362d3Smrgdrmmode_output_dpms(xf86OutputPtr output, int mode) 976de2362d3Smrg{ 977de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 978de2362d3Smrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 979de2362d3Smrg drmmode_ptr drmmode = drmmode_output->drmmode; 980de2362d3Smrg 981de2362d3Smrg if (mode != DPMSModeOn && output->crtc) 982de2362d3Smrg drmmode_do_crtc_dpms(output->crtc, mode); 983de2362d3Smrg 984de2362d3Smrg drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id, 985de2362d3Smrg drmmode_output->dpms_enum_id, mode); 986de2362d3Smrg 987de2362d3Smrg if (mode == DPMSModeOn && output->crtc) 988de2362d3Smrg drmmode_do_crtc_dpms(output->crtc, mode); 989de2362d3Smrg} 990de2362d3Smrg 991de2362d3Smrg 992de2362d3Smrgstatic Bool 993de2362d3Smrgdrmmode_property_ignore(drmModePropertyPtr prop) 994de2362d3Smrg{ 995de2362d3Smrg if (!prop) 996de2362d3Smrg return TRUE; 997de2362d3Smrg /* ignore blob prop */ 998de2362d3Smrg if (prop->flags & DRM_MODE_PROP_BLOB) 999de2362d3Smrg return TRUE; 1000de2362d3Smrg /* ignore standard property */ 1001de2362d3Smrg if (!strcmp(prop->name, "EDID") || 1002de2362d3Smrg !strcmp(prop->name, "DPMS")) 1003de2362d3Smrg return TRUE; 1004de2362d3Smrg 1005de2362d3Smrg return FALSE; 1006de2362d3Smrg} 1007de2362d3Smrg 1008de2362d3Smrgstatic void 1009de2362d3Smrgdrmmode_output_create_resources(xf86OutputPtr output) 1010de2362d3Smrg{ 1011de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1012de2362d3Smrg drmModeConnectorPtr mode_output = drmmode_output->mode_output; 1013de2362d3Smrg drmmode_ptr drmmode = drmmode_output->drmmode; 1014de2362d3Smrg drmModePropertyPtr drmmode_prop; 1015de2362d3Smrg int i, j, err; 1016de2362d3Smrg 1017de2362d3Smrg drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec)); 1018de2362d3Smrg if (!drmmode_output->props) 1019de2362d3Smrg return; 1020de2362d3Smrg 1021de2362d3Smrg drmmode_output->num_props = 0; 1022de2362d3Smrg for (i = 0, j = 0; i < mode_output->count_props; i++) { 1023de2362d3Smrg drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]); 1024de2362d3Smrg if (drmmode_property_ignore(drmmode_prop)) { 1025de2362d3Smrg drmModeFreeProperty(drmmode_prop); 1026de2362d3Smrg continue; 1027de2362d3Smrg } 1028de2362d3Smrg drmmode_output->props[j].mode_prop = drmmode_prop; 1029de2362d3Smrg drmmode_output->props[j].value = mode_output->prop_values[i]; 1030de2362d3Smrg drmmode_output->num_props++; 1031de2362d3Smrg j++; 1032de2362d3Smrg } 1033de2362d3Smrg 1034de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 1035de2362d3Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 1036de2362d3Smrg drmmode_prop = p->mode_prop; 1037de2362d3Smrg 1038de2362d3Smrg if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 1039de2362d3Smrg INT32 range[2]; 1040de2362d3Smrg INT32 value = p->value; 1041de2362d3Smrg 1042de2362d3Smrg p->num_atoms = 1; 1043de2362d3Smrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 1044de2362d3Smrg if (!p->atoms) 1045de2362d3Smrg continue; 1046de2362d3Smrg p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 1047de2362d3Smrg range[0] = drmmode_prop->values[0]; 1048de2362d3Smrg range[1] = drmmode_prop->values[1]; 1049de2362d3Smrg err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 1050de2362d3Smrg FALSE, TRUE, 1051de2362d3Smrg drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 1052de2362d3Smrg 2, range); 1053de2362d3Smrg if (err != 0) { 1054de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1055de2362d3Smrg "RRConfigureOutputProperty error, %d\n", err); 1056de2362d3Smrg } 1057de2362d3Smrg err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 1058de2362d3Smrg XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, TRUE); 1059de2362d3Smrg if (err != 0) { 1060de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1061de2362d3Smrg "RRChangeOutputProperty error, %d\n", err); 1062de2362d3Smrg } 1063de2362d3Smrg } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 1064de2362d3Smrg p->num_atoms = drmmode_prop->count_enums + 1; 1065de2362d3Smrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 1066de2362d3Smrg if (!p->atoms) 1067de2362d3Smrg continue; 1068de2362d3Smrg p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 1069de2362d3Smrg for (j = 1; j <= drmmode_prop->count_enums; j++) { 1070de2362d3Smrg struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; 1071de2362d3Smrg p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); 1072de2362d3Smrg } 1073de2362d3Smrg err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 1074de2362d3Smrg FALSE, FALSE, 1075de2362d3Smrg drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 1076de2362d3Smrg p->num_atoms - 1, (INT32 *)&p->atoms[1]); 1077de2362d3Smrg if (err != 0) { 1078de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1079de2362d3Smrg "RRConfigureOutputProperty error, %d\n", err); 1080de2362d3Smrg } 1081de2362d3Smrg for (j = 0; j < drmmode_prop->count_enums; j++) 1082de2362d3Smrg if (drmmode_prop->enums[j].value == p->value) 1083de2362d3Smrg break; 1084de2362d3Smrg /* there's always a matching value */ 1085de2362d3Smrg err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 1086de2362d3Smrg XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE); 1087de2362d3Smrg if (err != 0) { 1088de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1089de2362d3Smrg "RRChangeOutputProperty error, %d\n", err); 1090de2362d3Smrg } 1091de2362d3Smrg } 1092de2362d3Smrg } 1093de2362d3Smrg} 1094de2362d3Smrg 1095de2362d3Smrgstatic Bool 1096de2362d3Smrgdrmmode_output_set_property(xf86OutputPtr output, Atom property, 1097de2362d3Smrg RRPropertyValuePtr value) 1098de2362d3Smrg{ 1099de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1100de2362d3Smrg drmmode_ptr drmmode = drmmode_output->drmmode; 1101de2362d3Smrg int i; 1102de2362d3Smrg 1103de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 1104de2362d3Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 1105de2362d3Smrg 1106de2362d3Smrg if (p->atoms[0] != property) 1107de2362d3Smrg continue; 1108de2362d3Smrg 1109de2362d3Smrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 1110de2362d3Smrg uint32_t val; 1111de2362d3Smrg 1112de2362d3Smrg if (value->type != XA_INTEGER || value->format != 32 || 1113de2362d3Smrg value->size != 1) 1114de2362d3Smrg return FALSE; 1115de2362d3Smrg val = *(uint32_t *)value->data; 1116de2362d3Smrg 1117de2362d3Smrg drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, 1118de2362d3Smrg p->mode_prop->prop_id, (uint64_t)val); 1119de2362d3Smrg return TRUE; 1120de2362d3Smrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 1121de2362d3Smrg Atom atom; 1122de2362d3Smrg const char *name; 1123de2362d3Smrg int j; 1124de2362d3Smrg 1125de2362d3Smrg if (value->type != XA_ATOM || value->format != 32 || value->size != 1) 1126de2362d3Smrg return FALSE; 1127de2362d3Smrg memcpy(&atom, value->data, 4); 1128de2362d3Smrg name = NameForAtom(atom); 1129de2362d3Smrg 1130de2362d3Smrg /* search for matching name string, then set its value down */ 1131de2362d3Smrg for (j = 0; j < p->mode_prop->count_enums; j++) { 1132de2362d3Smrg if (!strcmp(p->mode_prop->enums[j].name, name)) { 1133de2362d3Smrg drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, 1134de2362d3Smrg p->mode_prop->prop_id, p->mode_prop->enums[j].value); 1135de2362d3Smrg return TRUE; 1136de2362d3Smrg } 1137de2362d3Smrg } 1138de2362d3Smrg } 1139de2362d3Smrg } 1140de2362d3Smrg 1141de2362d3Smrg return TRUE; 1142de2362d3Smrg} 1143de2362d3Smrg 1144de2362d3Smrgstatic Bool 1145de2362d3Smrgdrmmode_output_get_property(xf86OutputPtr output, Atom property) 1146de2362d3Smrg{ 1147de2362d3Smrg return TRUE; 1148de2362d3Smrg} 1149de2362d3Smrg 1150de2362d3Smrgstatic const xf86OutputFuncsRec drmmode_output_funcs = { 1151de2362d3Smrg .dpms = drmmode_output_dpms, 1152de2362d3Smrg .create_resources = drmmode_output_create_resources, 1153de2362d3Smrg .set_property = drmmode_output_set_property, 1154de2362d3Smrg .get_property = drmmode_output_get_property, 1155de2362d3Smrg#if 0 1156de2362d3Smrg 1157de2362d3Smrg .save = drmmode_crt_save, 1158de2362d3Smrg .restore = drmmode_crt_restore, 1159de2362d3Smrg .mode_fixup = drmmode_crt_mode_fixup, 1160de2362d3Smrg .prepare = drmmode_output_prepare, 1161de2362d3Smrg .mode_set = drmmode_crt_mode_set, 1162de2362d3Smrg .commit = drmmode_output_commit, 1163de2362d3Smrg#endif 1164de2362d3Smrg .detect = drmmode_output_detect, 1165de2362d3Smrg .mode_valid = drmmode_output_mode_valid, 1166de2362d3Smrg 1167de2362d3Smrg .get_modes = drmmode_output_get_modes, 1168de2362d3Smrg .destroy = drmmode_output_destroy 1169de2362d3Smrg}; 1170de2362d3Smrg 1171de2362d3Smrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown, 1172de2362d3Smrg SubPixelHorizontalRGB, 1173de2362d3Smrg SubPixelHorizontalBGR, 1174de2362d3Smrg SubPixelVerticalRGB, 1175de2362d3Smrg SubPixelVerticalBGR, 1176de2362d3Smrg SubPixelNone }; 1177de2362d3Smrg 1178de2362d3Smrgconst char *output_names[] = { "None", 1179de2362d3Smrg "VGA", 1180de2362d3Smrg "DVI", 1181de2362d3Smrg "DVI", 1182de2362d3Smrg "DVI", 1183de2362d3Smrg "Composite", 1184de2362d3Smrg "S-video", 1185de2362d3Smrg "LVDS", 1186de2362d3Smrg "CTV", 1187de2362d3Smrg "DIN", 1188de2362d3Smrg "DisplayPort", 1189de2362d3Smrg "HDMI", 1190de2362d3Smrg "HDMI", 1191de2362d3Smrg "TV", 1192de2362d3Smrg "eDP" 1193de2362d3Smrg}; 1194de2362d3Smrg 1195de2362d3Smrg#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0])) 1196de2362d3Smrg 1197de2362d3Smrgstatic void 1198de2362d3Smrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num, int *num_dvi, int *num_hdmi) 1199de2362d3Smrg{ 1200de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1201de2362d3Smrg xf86OutputPtr output; 1202de2362d3Smrg drmModeConnectorPtr koutput; 1203de2362d3Smrg drmModeEncoderPtr *kencoders = NULL; 1204de2362d3Smrg drmmode_output_private_ptr drmmode_output; 1205de2362d3Smrg drmModePropertyPtr props; 1206de2362d3Smrg char name[32]; 1207de2362d3Smrg int i; 1208de2362d3Smrg const char *s; 1209de2362d3Smrg 1210de2362d3Smrg koutput = drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]); 1211de2362d3Smrg if (!koutput) 1212de2362d3Smrg return; 1213de2362d3Smrg 1214de2362d3Smrg kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); 1215de2362d3Smrg if (!kencoders) { 1216de2362d3Smrg goto out_free_encoders; 1217de2362d3Smrg } 1218de2362d3Smrg 1219de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) { 1220de2362d3Smrg kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]); 1221de2362d3Smrg if (!kencoders[i]) { 1222de2362d3Smrg goto out_free_encoders; 1223de2362d3Smrg } 1224de2362d3Smrg } 1225de2362d3Smrg 1226de2362d3Smrg if (koutput->connector_type >= NUM_OUTPUT_NAMES) 1227de2362d3Smrg snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, 1228de2362d3Smrg koutput->connector_type_id - 1); 1229de2362d3Smrg#ifdef RADEON_PIXMAP_SHARING 1230de2362d3Smrg else if (pScrn->is_gpu) 1231de2362d3Smrg snprintf(name, 32, "%s-%d-%d", 1232de2362d3Smrg output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, 1233de2362d3Smrg koutput->connector_type_id - 1); 1234de2362d3Smrg#endif 1235de2362d3Smrg else { 1236de2362d3Smrg /* need to do smart conversion here for compat with non-kms ATI driver */ 1237de2362d3Smrg if (koutput->connector_type_id == 1) { 1238de2362d3Smrg switch(koutput->connector_type) { 1239de2362d3Smrg case DRM_MODE_CONNECTOR_DVII: 1240de2362d3Smrg case DRM_MODE_CONNECTOR_DVID: 1241de2362d3Smrg case DRM_MODE_CONNECTOR_DVIA: 1242de2362d3Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi); 1243de2362d3Smrg (*num_dvi)++; 1244de2362d3Smrg break; 1245de2362d3Smrg case DRM_MODE_CONNECTOR_HDMIA: 1246de2362d3Smrg case DRM_MODE_CONNECTOR_HDMIB: 1247de2362d3Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi); 1248de2362d3Smrg (*num_hdmi)++; 1249de2362d3Smrg break; 1250de2362d3Smrg case DRM_MODE_CONNECTOR_VGA: 1251de2362d3Smrg case DRM_MODE_CONNECTOR_DisplayPort: 1252de2362d3Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], 1253de2362d3Smrg koutput->connector_type_id - 1); 1254de2362d3Smrg break; 1255de2362d3Smrg default: 1256de2362d3Smrg snprintf(name, 32, "%s", output_names[koutput->connector_type]); 1257de2362d3Smrg break; 1258de2362d3Smrg } 1259de2362d3Smrg } else { 1260de2362d3Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], 1261de2362d3Smrg koutput->connector_type_id - 1); 1262de2362d3Smrg } 1263de2362d3Smrg } 1264de2362d3Smrg 1265de2362d3Smrg if (xf86IsEntityShared(pScrn->entityList[0])) { 1266de2362d3Smrg if ((s = xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) { 1267de2362d3Smrg if (!RADEONZaphodStringMatches(pScrn, s, name)) 1268de2362d3Smrg goto out_free_encoders; 1269de2362d3Smrg } else { 1270de2362d3Smrg if (info->IsPrimary && (num != 0)) 1271de2362d3Smrg goto out_free_encoders; 1272de2362d3Smrg else if (info->IsSecondary && (num != 1)) 1273de2362d3Smrg goto out_free_encoders; 1274de2362d3Smrg } 1275de2362d3Smrg } 1276de2362d3Smrg 1277de2362d3Smrg output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name); 1278de2362d3Smrg if (!output) { 1279de2362d3Smrg goto out_free_encoders; 1280de2362d3Smrg } 1281de2362d3Smrg 1282de2362d3Smrg drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); 1283de2362d3Smrg if (!drmmode_output) { 1284de2362d3Smrg xf86OutputDestroy(output); 1285de2362d3Smrg goto out_free_encoders; 1286de2362d3Smrg } 1287de2362d3Smrg 1288de2362d3Smrg drmmode_output->output_id = drmmode->mode_res->connectors[num]; 1289de2362d3Smrg drmmode_output->mode_output = koutput; 1290de2362d3Smrg drmmode_output->mode_encoders = kencoders; 1291de2362d3Smrg drmmode_output->drmmode = drmmode; 1292de2362d3Smrg output->mm_width = koutput->mmWidth; 1293de2362d3Smrg output->mm_height = koutput->mmHeight; 1294de2362d3Smrg 1295de2362d3Smrg output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 1296de2362d3Smrg output->interlaceAllowed = TRUE; 1297de2362d3Smrg output->doubleScanAllowed = TRUE; 1298de2362d3Smrg output->driver_private = drmmode_output; 1299de2362d3Smrg 1300de2362d3Smrg output->possible_crtcs = 0xffffffff; 1301de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) { 1302de2362d3Smrg output->possible_crtcs &= kencoders[i]->possible_crtcs; 1303de2362d3Smrg } 1304de2362d3Smrg /* work out the possible clones later */ 1305de2362d3Smrg output->possible_clones = 0; 1306de2362d3Smrg 1307de2362d3Smrg for (i = 0; i < koutput->count_props; i++) { 1308de2362d3Smrg props = drmModeGetProperty(drmmode->fd, koutput->props[i]); 1309de2362d3Smrg if (props && (props->flags & DRM_MODE_PROP_ENUM)) { 1310de2362d3Smrg if (!strcmp(props->name, "DPMS")) { 1311de2362d3Smrg drmmode_output->dpms_enum_id = koutput->props[i]; 1312de2362d3Smrg drmModeFreeProperty(props); 1313de2362d3Smrg break; 1314de2362d3Smrg } 1315de2362d3Smrg drmModeFreeProperty(props); 1316de2362d3Smrg } 1317de2362d3Smrg } 1318de2362d3Smrg 1319de2362d3Smrg return; 1320de2362d3Smrgout_free_encoders: 1321de2362d3Smrg if (kencoders){ 1322de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) 1323de2362d3Smrg drmModeFreeEncoder(kencoders[i]); 1324de2362d3Smrg free(kencoders); 1325de2362d3Smrg } 1326de2362d3Smrg drmModeFreeConnector(koutput); 1327de2362d3Smrg 1328de2362d3Smrg} 1329de2362d3Smrg 1330de2362d3Smrguint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output) 1331de2362d3Smrg{ 1332de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private, clone_drmout; 1333de2362d3Smrg int i; 1334de2362d3Smrg xf86OutputPtr clone_output; 1335de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1336de2362d3Smrg int index_mask = 0; 1337de2362d3Smrg 1338de2362d3Smrg if (drmmode_output->enc_clone_mask == 0) 1339de2362d3Smrg return index_mask; 1340de2362d3Smrg 1341de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 1342de2362d3Smrg clone_output = xf86_config->output[i]; 1343de2362d3Smrg clone_drmout = clone_output->driver_private; 1344de2362d3Smrg if (output == clone_output) 1345de2362d3Smrg continue; 1346de2362d3Smrg 1347de2362d3Smrg if (clone_drmout->enc_mask == 0) 1348de2362d3Smrg continue; 1349de2362d3Smrg if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask) 1350de2362d3Smrg index_mask |= (1 << i); 1351de2362d3Smrg } 1352de2362d3Smrg return index_mask; 1353de2362d3Smrg} 1354de2362d3Smrg 1355de2362d3Smrg 1356de2362d3Smrgstatic void 1357de2362d3Smrgdrmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 1358de2362d3Smrg{ 1359de2362d3Smrg int i, j; 1360de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1361de2362d3Smrg 1362de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 1363de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 1364de2362d3Smrg drmmode_output_private_ptr drmmode_output; 1365de2362d3Smrg 1366de2362d3Smrg drmmode_output = output->driver_private; 1367de2362d3Smrg drmmode_output->enc_clone_mask = 0xff; 1368de2362d3Smrg /* and all the possible encoder clones for this output together */ 1369de2362d3Smrg for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) 1370de2362d3Smrg { 1371de2362d3Smrg int k; 1372de2362d3Smrg for (k = 0; k < drmmode->mode_res->count_encoders; k++) { 1373de2362d3Smrg if (drmmode->mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id) 1374de2362d3Smrg drmmode_output->enc_mask |= (1 << k); 1375de2362d3Smrg } 1376de2362d3Smrg 1377de2362d3Smrg drmmode_output->enc_clone_mask &= drmmode_output->mode_encoders[j]->possible_clones; 1378de2362d3Smrg } 1379de2362d3Smrg } 1380de2362d3Smrg 1381de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 1382de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 1383de2362d3Smrg output->possible_clones = find_clones(scrn, output); 1384de2362d3Smrg } 1385de2362d3Smrg} 1386de2362d3Smrg 1387de2362d3Smrg/* returns height alignment in pixels */ 1388de2362d3Smrgint drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling) 1389de2362d3Smrg{ 1390de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 1391de2362d3Smrg int height_align = 1; 1392de2362d3Smrg 1393de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 1394de2362d3Smrg if (tiling & RADEON_TILING_MACRO) 1395de2362d3Smrg height_align = info->num_channels * 8; 1396de2362d3Smrg else if (tiling & RADEON_TILING_MICRO) 1397de2362d3Smrg height_align = 8; 1398de2362d3Smrg else 1399de2362d3Smrg height_align = 8; 1400de2362d3Smrg } else { 1401de2362d3Smrg if (tiling & RADEON_TILING_MICRO_SQUARE) 1402de2362d3Smrg height_align = 32; 1403de2362d3Smrg else if (tiling) 1404de2362d3Smrg height_align = 16; 1405de2362d3Smrg else 1406de2362d3Smrg height_align = 1; 1407de2362d3Smrg } 1408de2362d3Smrg return height_align; 1409de2362d3Smrg} 1410de2362d3Smrg 1411de2362d3Smrg/* returns pitch alignment in pixels */ 1412de2362d3Smrgint drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling) 1413de2362d3Smrg{ 1414de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 1415de2362d3Smrg int pitch_align = 1; 1416de2362d3Smrg 1417de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 1418de2362d3Smrg if (tiling & RADEON_TILING_MACRO) { 1419de2362d3Smrg /* general surface requirements */ 1420de2362d3Smrg pitch_align = MAX(info->num_banks, 1421de2362d3Smrg (((info->group_bytes / 8) / bpe) * info->num_banks)) * 8; 1422de2362d3Smrg /* further restrictions for scanout */ 1423de2362d3Smrg pitch_align = MAX(info->num_banks * 8, pitch_align); 1424de2362d3Smrg } else if (tiling & RADEON_TILING_MICRO) { 1425de2362d3Smrg /* general surface requirements */ 1426de2362d3Smrg pitch_align = MAX(8, (info->group_bytes / (8 * bpe))); 1427de2362d3Smrg /* further restrictions for scanout */ 1428de2362d3Smrg pitch_align = MAX(info->group_bytes / bpe, pitch_align); 1429de2362d3Smrg } else { 1430de2362d3Smrg if (info->have_tiling_info) 1431de2362d3Smrg /* linear aligned requirements */ 1432de2362d3Smrg pitch_align = MAX(64, info->group_bytes / bpe); 1433de2362d3Smrg else 1434de2362d3Smrg /* default to 512 elements if we don't know the real 1435de2362d3Smrg * group size otherwise the kernel may reject the CS 1436de2362d3Smrg * if the group sizes don't match as the pitch won't 1437de2362d3Smrg * be aligned properly. 1438de2362d3Smrg */ 1439de2362d3Smrg pitch_align = 512; 1440de2362d3Smrg } 1441de2362d3Smrg } else { 1442de2362d3Smrg /* general surface requirements */ 1443de2362d3Smrg if (tiling) 1444de2362d3Smrg pitch_align = 256 / bpe; 1445de2362d3Smrg else 1446de2362d3Smrg pitch_align = 64; 1447de2362d3Smrg } 1448de2362d3Smrg return pitch_align; 1449de2362d3Smrg} 1450de2362d3Smrg 1451de2362d3Smrg/* returns base alignment in bytes */ 1452de2362d3Smrgint drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling) 1453de2362d3Smrg{ 1454de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 1455de2362d3Smrg int pixel_align = drmmode_get_pitch_align(scrn, bpe, tiling); 1456de2362d3Smrg int height_align = drmmode_get_height_align(scrn, tiling); 1457de2362d3Smrg int base_align = RADEON_GPU_PAGE_SIZE; 1458de2362d3Smrg 1459de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 1460de2362d3Smrg if (tiling & RADEON_TILING_MACRO) 1461de2362d3Smrg base_align = MAX(info->num_banks * info->num_channels * 8 * 8 * bpe, 1462de2362d3Smrg pixel_align * bpe * height_align); 1463de2362d3Smrg else { 1464de2362d3Smrg if (info->have_tiling_info) 1465de2362d3Smrg base_align = info->group_bytes; 1466de2362d3Smrg else 1467de2362d3Smrg /* default to 512 if we don't know the real 1468de2362d3Smrg * group size otherwise the kernel may reject the CS 1469de2362d3Smrg * if the group sizes don't match as the base won't 1470de2362d3Smrg * be aligned properly. 1471de2362d3Smrg */ 1472de2362d3Smrg base_align = 512; 1473de2362d3Smrg } 1474de2362d3Smrg } 1475de2362d3Smrg return base_align; 1476de2362d3Smrg} 1477de2362d3Smrg 1478de2362d3Smrgstatic Bool 1479de2362d3Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) 1480de2362d3Smrg{ 1481de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1482de2362d3Smrg drmmode_crtc_private_ptr 1483de2362d3Smrg drmmode_crtc = xf86_config->crtc[0]->driver_private; 1484de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 1485de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 1486de2362d3Smrg struct radeon_bo *old_front = NULL; 1487de2362d3Smrg Bool ret; 1488de2362d3Smrg ScreenPtr screen = xf86ScrnToScreen(scrn); 1489de2362d3Smrg uint32_t old_fb_id; 1490de2362d3Smrg int i, pitch, old_width, old_height, old_pitch; 1491de2362d3Smrg uint32_t screen_size; 1492de2362d3Smrg int cpp = info->pixel_bytes; 1493de2362d3Smrg struct radeon_bo *front_bo; 1494de2362d3Smrg struct radeon_surface surface; 1495de2362d3Smrg struct radeon_surface *psurface; 1496de2362d3Smrg uint32_t tiling_flags = 0, base_align; 1497de2362d3Smrg PixmapPtr ppix = screen->GetScreenPixmap(screen); 1498de2362d3Smrg void *fb_shadow; 1499de2362d3Smrg 1500de2362d3Smrg if (scrn->virtualX == width && scrn->virtualY == height) 1501de2362d3Smrg return TRUE; 1502de2362d3Smrg 1503de2362d3Smrg front_bo = info->front_bo; 1504de2362d3Smrg radeon_cs_flush_indirect(scrn); 1505de2362d3Smrg 1506de2362d3Smrg if (front_bo) 1507de2362d3Smrg radeon_bo_wait(front_bo); 1508de2362d3Smrg 1509de2362d3Smrg if (info->allowColorTiling) { 1510de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 1511de2362d3Smrg if (info->allowColorTiling2D) { 1512de2362d3Smrg tiling_flags |= RADEON_TILING_MACRO; 1513de2362d3Smrg } else { 1514de2362d3Smrg tiling_flags |= RADEON_TILING_MICRO; 1515de2362d3Smrg } 1516de2362d3Smrg } else 1517de2362d3Smrg tiling_flags |= RADEON_TILING_MACRO; 1518de2362d3Smrg } 1519de2362d3Smrg 1520de2362d3Smrg pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(scrn, cpp, tiling_flags)) * cpp; 1521de2362d3Smrg height = RADEON_ALIGN(height, drmmode_get_height_align(scrn, tiling_flags)); 1522de2362d3Smrg screen_size = RADEON_ALIGN(pitch * height, RADEON_GPU_PAGE_SIZE); 1523de2362d3Smrg base_align = 4096; 1524de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 1525de2362d3Smrg memset(&surface, 0, sizeof(struct radeon_surface)); 1526de2362d3Smrg surface.npix_x = width; 1527de2362d3Smrg surface.npix_y = height; 1528de2362d3Smrg surface.npix_z = 1; 1529de2362d3Smrg surface.blk_w = 1; 1530de2362d3Smrg surface.blk_h = 1; 1531de2362d3Smrg surface.blk_d = 1; 1532de2362d3Smrg surface.array_size = 1; 1533de2362d3Smrg surface.last_level = 0; 1534de2362d3Smrg surface.bpe = cpp; 1535de2362d3Smrg surface.nsamples = 1; 1536de2362d3Smrg surface.flags = RADEON_SURF_SCANOUT; 1537de2362d3Smrg /* we are requiring a recent enough libdrm version */ 1538de2362d3Smrg surface.flags |= RADEON_SURF_HAS_TILE_MODE_INDEX; 1539de2362d3Smrg surface.flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); 1540de2362d3Smrg surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR_ALIGNED, MODE); 1541de2362d3Smrg if (tiling_flags & RADEON_TILING_MICRO) { 1542de2362d3Smrg surface.flags = RADEON_SURF_CLR(surface.flags, MODE); 1543de2362d3Smrg surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE); 1544de2362d3Smrg } 1545de2362d3Smrg if (tiling_flags & RADEON_TILING_MACRO) { 1546de2362d3Smrg surface.flags = RADEON_SURF_CLR(surface.flags, MODE); 1547de2362d3Smrg surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE); 1548de2362d3Smrg } 1549de2362d3Smrg if (radeon_surface_best(info->surf_man, &surface)) { 1550de2362d3Smrg return FALSE; 1551de2362d3Smrg } 1552de2362d3Smrg if (radeon_surface_init(info->surf_man, &surface)) { 1553de2362d3Smrg return FALSE; 1554de2362d3Smrg } 1555de2362d3Smrg screen_size = surface.bo_size; 1556de2362d3Smrg base_align = surface.bo_alignment; 1557de2362d3Smrg pitch = surface.level[0].pitch_bytes; 1558de2362d3Smrg tiling_flags = 0; 1559de2362d3Smrg switch (surface.level[0].mode) { 1560de2362d3Smrg case RADEON_SURF_MODE_2D: 1561de2362d3Smrg tiling_flags |= RADEON_TILING_MACRO; 1562de2362d3Smrg tiling_flags |= surface.bankw << RADEON_TILING_EG_BANKW_SHIFT; 1563de2362d3Smrg tiling_flags |= surface.bankh << RADEON_TILING_EG_BANKH_SHIFT; 1564de2362d3Smrg tiling_flags |= surface.mtilea << RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT; 1565de2362d3Smrg tiling_flags |= eg_tile_split(surface.tile_split) << RADEON_TILING_EG_TILE_SPLIT_SHIFT; 1566de2362d3Smrg break; 1567de2362d3Smrg case RADEON_SURF_MODE_1D: 1568de2362d3Smrg tiling_flags |= RADEON_TILING_MICRO; 1569de2362d3Smrg break; 1570de2362d3Smrg default: 1571de2362d3Smrg break; 1572de2362d3Smrg } 1573de2362d3Smrg info->front_surface = surface; 1574de2362d3Smrg } 1575de2362d3Smrg 1576de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_INFO, 1577de2362d3Smrg "Allocate new frame buffer %dx%d stride %d\n", 1578de2362d3Smrg width, height, pitch / cpp); 1579de2362d3Smrg 1580de2362d3Smrg old_width = scrn->virtualX; 1581de2362d3Smrg old_height = scrn->virtualY; 1582de2362d3Smrg old_pitch = scrn->displayWidth; 1583de2362d3Smrg old_fb_id = drmmode->fb_id; 1584de2362d3Smrg old_front = info->front_bo; 1585de2362d3Smrg 1586de2362d3Smrg scrn->virtualX = width; 1587de2362d3Smrg scrn->virtualY = height; 1588de2362d3Smrg scrn->displayWidth = pitch / cpp; 1589de2362d3Smrg 1590de2362d3Smrg info->front_bo = radeon_bo_open(info->bufmgr, 0, screen_size, base_align, RADEON_GEM_DOMAIN_VRAM, 0); 1591de2362d3Smrg if (!info->front_bo) 1592de2362d3Smrg goto fail; 1593de2362d3Smrg 1594de2362d3Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN 1595de2362d3Smrg switch (cpp) { 1596de2362d3Smrg case 4: 1597de2362d3Smrg tiling_flags |= RADEON_TILING_SWAP_32BIT; 1598de2362d3Smrg break; 1599de2362d3Smrg case 2: 1600de2362d3Smrg tiling_flags |= RADEON_TILING_SWAP_16BIT; 1601de2362d3Smrg break; 1602de2362d3Smrg } 1603de2362d3Smrg if (info->ChipFamily < CHIP_FAMILY_R600 && 1604de2362d3Smrg info->r600_shadow_fb && tiling_flags) 1605de2362d3Smrg tiling_flags |= RADEON_TILING_SURFACE; 1606de2362d3Smrg#endif 1607de2362d3Smrg if (tiling_flags) 1608de2362d3Smrg radeon_bo_set_tiling(info->front_bo, tiling_flags, pitch); 1609de2362d3Smrg 1610de2362d3Smrg ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth, 1611de2362d3Smrg scrn->bitsPerPixel, pitch, 1612de2362d3Smrg info->front_bo->handle, 1613de2362d3Smrg &drmmode->fb_id); 1614de2362d3Smrg if (ret) 1615de2362d3Smrg goto fail; 1616de2362d3Smrg 1617de2362d3Smrg if (!info->r600_shadow_fb) { 1618de2362d3Smrg radeon_set_pixmap_bo(ppix, info->front_bo); 1619de2362d3Smrg psurface = radeon_get_pixmap_surface(ppix); 1620de2362d3Smrg *psurface = info->front_surface; 1621de2362d3Smrg screen->ModifyPixmapHeader(ppix, 1622de2362d3Smrg width, height, -1, -1, pitch, NULL); 1623de2362d3Smrg } else { 1624de2362d3Smrg if (radeon_bo_map(info->front_bo, 1)) 1625de2362d3Smrg goto fail; 1626de2362d3Smrg fb_shadow = calloc(1, screen_size); 1627de2362d3Smrg if (fb_shadow == NULL) 1628de2362d3Smrg goto fail; 1629de2362d3Smrg free(info->fb_shadow); 1630de2362d3Smrg info->fb_shadow = fb_shadow; 1631de2362d3Smrg screen->ModifyPixmapHeader(ppix, 1632de2362d3Smrg width, height, -1, -1, pitch, 1633de2362d3Smrg info->fb_shadow); 1634de2362d3Smrg } 1635de2362d3Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,9,99,1,0) 1636de2362d3Smrg scrn->pixmapPrivate.ptr = ppix->devPrivate.ptr; 1637de2362d3Smrg#endif 1638de2362d3Smrg 1639de2362d3Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 1640de2362d3Smrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 1641de2362d3Smrg 1642de2362d3Smrg if (!crtc->enabled) 1643de2362d3Smrg continue; 1644de2362d3Smrg 1645de2362d3Smrg drmmode_set_mode_major(crtc, &crtc->mode, 1646de2362d3Smrg crtc->rotation, crtc->x, crtc->y); 1647de2362d3Smrg } 1648de2362d3Smrg 1649de2362d3Smrg if (info->use_glamor) 1650de2362d3Smrg radeon_glamor_create_screen_resources(scrn->pScreen); 1651de2362d3Smrg 1652de2362d3Smrg if (old_fb_id) 1653de2362d3Smrg drmModeRmFB(drmmode->fd, old_fb_id); 1654de2362d3Smrg if (old_front) 1655de2362d3Smrg radeon_bo_unref(old_front); 1656de2362d3Smrg 1657de2362d3Smrg radeon_kms_update_vram_limit(scrn, screen_size); 1658de2362d3Smrg return TRUE; 1659de2362d3Smrg 1660de2362d3Smrg fail: 1661de2362d3Smrg if (info->front_bo) 1662de2362d3Smrg radeon_bo_unref(info->front_bo); 1663de2362d3Smrg info->front_bo = old_front; 1664de2362d3Smrg scrn->virtualX = old_width; 1665de2362d3Smrg scrn->virtualY = old_height; 1666de2362d3Smrg scrn->displayWidth = old_pitch; 1667de2362d3Smrg drmmode->fb_id = old_fb_id; 1668de2362d3Smrg 1669de2362d3Smrg return FALSE; 1670de2362d3Smrg} 1671de2362d3Smrg 1672de2362d3Smrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { 1673de2362d3Smrg drmmode_xf86crtc_resize 1674de2362d3Smrg}; 1675de2362d3Smrg 1676de2362d3Smrgstatic void 1677de2362d3Smrgdrmmode_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec, 1678de2362d3Smrg unsigned int tv_usec, void *event_data) 1679de2362d3Smrg{ 1680de2362d3Smrg radeon_dri2_frame_event_handler(frame, tv_sec, tv_usec, event_data); 1681de2362d3Smrg} 1682de2362d3Smrg 1683de2362d3Smrgstatic void 1684de2362d3Smrgdrmmode_flip_handler(int fd, unsigned int frame, unsigned int tv_sec, 1685de2362d3Smrg unsigned int tv_usec, void *event_data) 1686de2362d3Smrg{ 1687de2362d3Smrg drmmode_flipevtcarrier_ptr flipcarrier = event_data; 1688de2362d3Smrg drmmode_flipdata_ptr flipdata = flipcarrier->flipdata; 1689de2362d3Smrg drmmode_ptr drmmode = flipdata->drmmode; 1690de2362d3Smrg 1691de2362d3Smrg /* Is this the event whose info shall be delivered to higher level? */ 1692de2362d3Smrg if (flipcarrier->dispatch_me) { 1693de2362d3Smrg /* Yes: Cache msc, ust for later delivery. */ 1694de2362d3Smrg flipdata->fe_frame = frame; 1695de2362d3Smrg flipdata->fe_tv_sec = tv_sec; 1696de2362d3Smrg flipdata->fe_tv_usec = tv_usec; 1697de2362d3Smrg } 1698de2362d3Smrg free(flipcarrier); 1699de2362d3Smrg 1700de2362d3Smrg /* Last crtc completed flip? */ 1701de2362d3Smrg flipdata->flip_count--; 1702de2362d3Smrg if (flipdata->flip_count > 0) 1703de2362d3Smrg return; 1704de2362d3Smrg 1705de2362d3Smrg /* Release framebuffer */ 1706de2362d3Smrg drmModeRmFB(drmmode->fd, flipdata->old_fb_id); 1707de2362d3Smrg 1708de2362d3Smrg if (flipdata->event_data == NULL) 1709de2362d3Smrg return; 1710de2362d3Smrg 1711de2362d3Smrg /* Deliver cached msc, ust from reference crtc to flip event handler */ 1712de2362d3Smrg radeon_dri2_flip_event_handler(flipdata->fe_frame, flipdata->fe_tv_sec, 1713de2362d3Smrg flipdata->fe_tv_usec, flipdata->event_data); 1714de2362d3Smrg 1715de2362d3Smrg free(flipdata); 1716de2362d3Smrg} 1717de2362d3Smrg 1718de2362d3Smrg 1719de2362d3Smrgstatic void 1720de2362d3Smrgdrm_wakeup_handler(pointer data, int err, pointer p) 1721de2362d3Smrg{ 1722de2362d3Smrg drmmode_ptr drmmode = data; 1723de2362d3Smrg fd_set *read_mask = p; 1724de2362d3Smrg 1725de2362d3Smrg if (err >= 0 && FD_ISSET(drmmode->fd, read_mask)) { 1726de2362d3Smrg drmHandleEvent(drmmode->fd, &drmmode->event_context); 1727de2362d3Smrg } 1728de2362d3Smrg} 1729de2362d3Smrg 1730de2362d3SmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) 1731de2362d3Smrg{ 1732de2362d3Smrg int i, num_dvi = 0, num_hdmi = 0; 1733de2362d3Smrg 1734de2362d3Smrg xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); 1735de2362d3Smrg 1736de2362d3Smrg drmmode->scrn = pScrn; 1737de2362d3Smrg drmmode->cpp = cpp; 1738de2362d3Smrg drmmode->mode_res = drmModeGetResources(drmmode->fd); 1739de2362d3Smrg if (!drmmode->mode_res) 1740de2362d3Smrg return FALSE; 1741de2362d3Smrg 1742de2362d3Smrg xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width, drmmode->mode_res->max_height); 1743de2362d3Smrg for (i = 0; i < drmmode->mode_res->count_crtcs; i++) 1744de2362d3Smrg if (!xf86IsEntityShared(pScrn->entityList[0]) || pScrn->confScreen->device->screen == i) 1745de2362d3Smrg drmmode_crtc_init(pScrn, drmmode, i); 1746de2362d3Smrg 1747de2362d3Smrg for (i = 0; i < drmmode->mode_res->count_connectors; i++) 1748de2362d3Smrg drmmode_output_init(pScrn, drmmode, i, &num_dvi, &num_hdmi); 1749de2362d3Smrg 1750de2362d3Smrg /* workout clones */ 1751de2362d3Smrg drmmode_clones_init(pScrn, drmmode); 1752de2362d3Smrg 1753de2362d3Smrg#ifdef RADEON_PIXMAP_SHARING 1754de2362d3Smrg xf86ProviderSetup(pScrn, NULL, "radeon"); 1755de2362d3Smrg#endif 1756de2362d3Smrg 1757de2362d3Smrg xf86InitialConfiguration(pScrn, TRUE); 1758de2362d3Smrg 1759de2362d3Smrg drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION; 1760de2362d3Smrg drmmode->event_context.vblank_handler = drmmode_vblank_handler; 1761de2362d3Smrg drmmode->event_context.page_flip_handler = drmmode_flip_handler; 1762de2362d3Smrg 1763de2362d3Smrg return TRUE; 1764de2362d3Smrg} 1765de2362d3Smrg 1766de2362d3Smrgvoid drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 1767de2362d3Smrg{ 1768de2362d3Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 1769de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1770de2362d3Smrg 1771de2362d3Smrg if (info->dri2.pKernelDRMVersion->version_minor < 4) 1772de2362d3Smrg return; 1773de2362d3Smrg 1774de2362d3Smrg info->drmmode_inited = TRUE; 1775de2362d3Smrg if (pRADEONEnt->fd_wakeup_registered != serverGeneration) { 1776de2362d3Smrg AddGeneralSocket(drmmode->fd); 1777de2362d3Smrg RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, 1778de2362d3Smrg drm_wakeup_handler, drmmode); 1779de2362d3Smrg pRADEONEnt->fd_wakeup_registered = serverGeneration; 1780de2362d3Smrg pRADEONEnt->fd_wakeup_ref = 1; 1781de2362d3Smrg } else 1782de2362d3Smrg pRADEONEnt->fd_wakeup_ref++; 1783de2362d3Smrg} 1784de2362d3Smrg 1785de2362d3Smrgvoid drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 1786de2362d3Smrg{ 1787de2362d3Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 1788de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1789de2362d3Smrg 1790de2362d3Smrg if (info->dri2.pKernelDRMVersion->version_minor < 4 || !info->drmmode_inited) 1791de2362d3Smrg return; 1792de2362d3Smrg 1793de2362d3Smrg if (pRADEONEnt->fd_wakeup_registered == serverGeneration && 1794de2362d3Smrg !--pRADEONEnt->fd_wakeup_ref) { 1795de2362d3Smrg RemoveGeneralSocket(drmmode->fd); 1796de2362d3Smrg RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, 1797de2362d3Smrg drm_wakeup_handler, drmmode); 1798de2362d3Smrg } 1799de2362d3Smrg} 1800de2362d3Smrg 1801de2362d3Smrg 1802de2362d3SmrgBool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, struct radeon_bo_manager *bufmgr) 1803de2362d3Smrg{ 1804de2362d3Smrg drmmode->bufmgr = bufmgr; 1805de2362d3Smrg return TRUE; 1806de2362d3Smrg} 1807de2362d3Smrg 1808de2362d3Smrg 1809de2362d3Smrg 1810de2362d3Smrgvoid drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id, struct radeon_bo *bo) 1811de2362d3Smrg{ 1812de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1813de2362d3Smrg xf86CrtcPtr crtc = xf86_config->crtc[id]; 1814de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1815de2362d3Smrg 1816de2362d3Smrg drmmode_crtc->cursor_bo = bo; 1817de2362d3Smrg} 1818de2362d3Smrg 1819de2362d3Smrgvoid drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y) 1820de2362d3Smrg{ 1821de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1822de2362d3Smrg xf86OutputPtr output = config->output[config->compat_output]; 1823de2362d3Smrg xf86CrtcPtr crtc = output->crtc; 1824de2362d3Smrg 1825de2362d3Smrg if (crtc && crtc->enabled) { 1826de2362d3Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 1827de2362d3Smrg x, y); 1828de2362d3Smrg } 1829de2362d3Smrg} 1830de2362d3Smrg 1831de2362d3SmrgBool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 1832de2362d3Smrg{ 1833de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1834de2362d3Smrg int c; 1835de2362d3Smrg 1836de2362d3Smrg drmmode_copy_fb(pScrn, drmmode); 1837de2362d3Smrg 1838de2362d3Smrg for (c = 0; c < config->num_crtc; c++) { 1839de2362d3Smrg xf86CrtcPtr crtc = config->crtc[c]; 1840de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1841de2362d3Smrg xf86OutputPtr output = NULL; 1842de2362d3Smrg int o; 1843de2362d3Smrg 1844de2362d3Smrg /* Skip disabled CRTCs */ 1845de2362d3Smrg if (!crtc->enabled) { 1846de2362d3Smrg drmmode_do_crtc_dpms(crtc, DPMSModeOff); 1847de2362d3Smrg drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 1848de2362d3Smrg 0, 0, 0, NULL, 0, NULL); 1849de2362d3Smrg continue; 1850de2362d3Smrg } 1851de2362d3Smrg 1852de2362d3Smrg if (config->output[config->compat_output]->crtc == crtc) 1853de2362d3Smrg output = config->output[config->compat_output]; 1854de2362d3Smrg else 1855de2362d3Smrg { 1856de2362d3Smrg for (o = 0; o < config->num_output; o++) 1857de2362d3Smrg if (config->output[o]->crtc == crtc) 1858de2362d3Smrg { 1859de2362d3Smrg output = config->output[o]; 1860de2362d3Smrg break; 1861de2362d3Smrg } 1862de2362d3Smrg } 1863de2362d3Smrg /* paranoia */ 1864de2362d3Smrg if (!output) 1865de2362d3Smrg continue; 1866de2362d3Smrg 1867de2362d3Smrg /* Mark that we'll need to re-set the mode for sure */ 1868de2362d3Smrg memset(&crtc->mode, 0, sizeof(crtc->mode)); 1869de2362d3Smrg if (!crtc->desiredMode.CrtcHDisplay) 1870de2362d3Smrg { 1871de2362d3Smrg DisplayModePtr mode = xf86OutputFindClosestMode (output, pScrn->currentMode); 1872de2362d3Smrg 1873de2362d3Smrg if (!mode) 1874de2362d3Smrg return FALSE; 1875de2362d3Smrg crtc->desiredMode = *mode; 1876de2362d3Smrg crtc->desiredRotation = RR_Rotate_0; 1877de2362d3Smrg crtc->desiredX = 0; 1878de2362d3Smrg crtc->desiredY = 0; 1879de2362d3Smrg } 1880de2362d3Smrg 1881de2362d3Smrg if (!crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, crtc->desiredRotation, 1882de2362d3Smrg crtc->desiredX, crtc->desiredY)) 1883de2362d3Smrg return FALSE; 1884de2362d3Smrg } 1885de2362d3Smrg return TRUE; 1886de2362d3Smrg} 1887de2362d3Smrg 1888de2362d3Smrgstatic void drmmode_load_palette(ScrnInfoPtr pScrn, int numColors, 1889de2362d3Smrg int *indices, LOCO *colors, VisualPtr pVisual) 1890de2362d3Smrg{ 1891de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1892de2362d3Smrg uint16_t lut_r[256], lut_g[256], lut_b[256]; 1893de2362d3Smrg int index, j, i; 1894de2362d3Smrg int c; 1895de2362d3Smrg 1896de2362d3Smrg for (c = 0; c < xf86_config->num_crtc; c++) { 1897de2362d3Smrg xf86CrtcPtr crtc = xf86_config->crtc[c]; 1898de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1899de2362d3Smrg 1900de2362d3Smrg for (i = 0 ; i < 256; i++) { 1901de2362d3Smrg lut_r[i] = drmmode_crtc->lut_r[i] << 6; 1902de2362d3Smrg lut_g[i] = drmmode_crtc->lut_g[i] << 6; 1903de2362d3Smrg lut_b[i] = drmmode_crtc->lut_b[i] << 6; 1904de2362d3Smrg } 1905de2362d3Smrg 1906de2362d3Smrg switch(pScrn->depth) { 1907de2362d3Smrg case 15: 1908de2362d3Smrg for (i = 0; i < numColors; i++) { 1909de2362d3Smrg index = indices[i]; 1910de2362d3Smrg for (j = 0; j < 8; j++) { 1911de2362d3Smrg lut_r[index * 8 + j] = colors[index].red << 6; 1912de2362d3Smrg lut_g[index * 8 + j] = colors[index].green << 6; 1913de2362d3Smrg lut_b[index * 8 + j] = colors[index].blue << 6; 1914de2362d3Smrg } 1915de2362d3Smrg } 1916de2362d3Smrg break; 1917de2362d3Smrg case 16: 1918de2362d3Smrg for (i = 0; i < numColors; i++) { 1919de2362d3Smrg index = indices[i]; 1920de2362d3Smrg 1921de2362d3Smrg if (i <= 31) { 1922de2362d3Smrg for (j = 0; j < 8; j++) { 1923de2362d3Smrg lut_r[index * 8 + j] = colors[index].red << 6; 1924de2362d3Smrg lut_b[index * 8 + j] = colors[index].blue << 6; 1925de2362d3Smrg } 1926de2362d3Smrg } 1927de2362d3Smrg 1928de2362d3Smrg for (j = 0; j < 4; j++) { 1929de2362d3Smrg lut_g[index * 4 + j] = colors[index].green << 6; 1930de2362d3Smrg } 1931de2362d3Smrg } 1932de2362d3Smrg break; 1933de2362d3Smrg default: 1934de2362d3Smrg for (i = 0; i < numColors; i++) { 1935de2362d3Smrg index = indices[i]; 1936de2362d3Smrg lut_r[index] = colors[index].red << 6; 1937de2362d3Smrg lut_g[index] = colors[index].green << 6; 1938de2362d3Smrg lut_b[index] = colors[index].blue << 6; 1939de2362d3Smrg } 1940de2362d3Smrg break; 1941de2362d3Smrg } 1942de2362d3Smrg 1943de2362d3Smrg /* Make the change through RandR */ 1944de2362d3Smrg if (crtc->randr_crtc) 1945de2362d3Smrg RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b); 1946de2362d3Smrg else 1947de2362d3Smrg crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256); 1948de2362d3Smrg } 1949de2362d3Smrg} 1950de2362d3Smrg 1951de2362d3SmrgBool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn) 1952de2362d3Smrg{ 1953de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1954de2362d3Smrg 1955de2362d3Smrg if (xf86_config->num_crtc) { 1956de2362d3Smrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 1957de2362d3Smrg "Initializing kms color map\n"); 1958de2362d3Smrg if (!miCreateDefColormap(pScreen)) 1959de2362d3Smrg return FALSE; 1960de2362d3Smrg /* all radeons support 10 bit CLUTs */ 1961de2362d3Smrg if (!xf86HandleColormaps(pScreen, 256, 10, 1962de2362d3Smrg drmmode_load_palette, NULL, 1963de2362d3Smrg CMAP_PALETTED_TRUECOLOR 1964de2362d3Smrg#if 0 /* This option messes up text mode! (eich@suse.de) */ 1965de2362d3Smrg | CMAP_LOAD_EVEN_IF_OFFSCREEN 1966de2362d3Smrg#endif 1967de2362d3Smrg | CMAP_RELOAD_ON_MODE_SWITCH)) 1968de2362d3Smrg return FALSE; 1969de2362d3Smrg } 1970de2362d3Smrg return TRUE; 1971de2362d3Smrg} 1972de2362d3Smrg 1973de2362d3Smrg#ifdef HAVE_LIBUDEV 1974de2362d3Smrgstatic void 1975de2362d3Smrgdrmmode_handle_uevents(int fd, void *closure) 1976de2362d3Smrg{ 1977de2362d3Smrg drmmode_ptr drmmode = closure; 1978de2362d3Smrg ScrnInfoPtr scrn = drmmode->scrn; 1979de2362d3Smrg struct udev_device *dev; 1980de2362d3Smrg dev = udev_monitor_receive_device(drmmode->uevent_monitor); 1981de2362d3Smrg if (!dev) 1982de2362d3Smrg return; 1983de2362d3Smrg 1984de2362d3Smrg RRGetInfo(xf86ScrnToScreen(scrn), TRUE); 1985de2362d3Smrg udev_device_unref(dev); 1986de2362d3Smrg} 1987de2362d3Smrg#endif 1988de2362d3Smrg 1989de2362d3Smrgvoid drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 1990de2362d3Smrg{ 1991de2362d3Smrg#ifdef HAVE_LIBUDEV 1992de2362d3Smrg struct udev *u; 1993de2362d3Smrg struct udev_monitor *mon; 1994de2362d3Smrg 1995de2362d3Smrg u = udev_new(); 1996de2362d3Smrg if (!u) 1997de2362d3Smrg return; 1998de2362d3Smrg mon = udev_monitor_new_from_netlink(u, "udev"); 1999de2362d3Smrg if (!mon) { 2000de2362d3Smrg udev_unref(u); 2001de2362d3Smrg return; 2002de2362d3Smrg } 2003de2362d3Smrg 2004de2362d3Smrg if (udev_monitor_filter_add_match_subsystem_devtype(mon, 2005de2362d3Smrg "drm", 2006de2362d3Smrg "drm_minor") < 0 || 2007de2362d3Smrg udev_monitor_enable_receiving(mon) < 0) { 2008de2362d3Smrg udev_monitor_unref(mon); 2009de2362d3Smrg udev_unref(u); 2010de2362d3Smrg return; 2011de2362d3Smrg } 2012de2362d3Smrg 2013de2362d3Smrg drmmode->uevent_handler = 2014de2362d3Smrg xf86AddGeneralHandler(udev_monitor_get_fd(mon), 2015de2362d3Smrg drmmode_handle_uevents, 2016de2362d3Smrg drmmode); 2017de2362d3Smrg 2018de2362d3Smrg drmmode->uevent_monitor = mon; 2019de2362d3Smrg#endif 2020de2362d3Smrg} 2021de2362d3Smrg 2022de2362d3Smrgvoid drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) 2023de2362d3Smrg{ 2024de2362d3Smrg#ifdef HAVE_LIBUDEV 2025de2362d3Smrg if (drmmode->uevent_handler) { 2026de2362d3Smrg struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); 2027de2362d3Smrg xf86RemoveGeneralHandler(drmmode->uevent_handler); 2028de2362d3Smrg 2029de2362d3Smrg udev_monitor_unref(drmmode->uevent_monitor); 2030de2362d3Smrg udev_unref(u); 2031de2362d3Smrg } 2032de2362d3Smrg#endif 2033de2362d3Smrg} 2034de2362d3Smrg 2035de2362d3SmrgBool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data, int ref_crtc_hw_id) 2036de2362d3Smrg{ 2037de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 2038de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2039de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; 2040de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 2041de2362d3Smrg unsigned int pitch; 2042de2362d3Smrg int i, old_fb_id; 2043de2362d3Smrg uint32_t tiling_flags = 0; 2044de2362d3Smrg int height, emitted = 0; 2045de2362d3Smrg drmmode_flipdata_ptr flipdata; 2046de2362d3Smrg drmmode_flipevtcarrier_ptr flipcarrier; 2047de2362d3Smrg 2048de2362d3Smrg if (info->allowColorTiling) { 2049de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) 2050de2362d3Smrg tiling_flags |= RADEON_TILING_MICRO; 2051de2362d3Smrg else 2052de2362d3Smrg tiling_flags |= RADEON_TILING_MACRO; 2053de2362d3Smrg } 2054de2362d3Smrg 2055de2362d3Smrg pitch = RADEON_ALIGN(scrn->displayWidth, drmmode_get_pitch_align(scrn, info->pixel_bytes, tiling_flags)) * 2056de2362d3Smrg info->pixel_bytes; 2057de2362d3Smrg height = RADEON_ALIGN(scrn->virtualY, drmmode_get_height_align(scrn, tiling_flags)); 2058de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) { 2059de2362d3Smrg pitch = info->front_surface.level[0].pitch_bytes; 2060de2362d3Smrg } 2061de2362d3Smrg 2062de2362d3Smrg /* 2063de2362d3Smrg * Create a new handle for the back buffer 2064de2362d3Smrg */ 2065de2362d3Smrg old_fb_id = drmmode->fb_id; 2066de2362d3Smrg if (drmModeAddFB(drmmode->fd, scrn->virtualX, height, 2067de2362d3Smrg scrn->depth, scrn->bitsPerPixel, pitch, 2068de2362d3Smrg new_front->handle, &drmmode->fb_id)) 2069de2362d3Smrg goto error_out; 2070de2362d3Smrg 2071de2362d3Smrg flipdata = calloc(1, sizeof(drmmode_flipdata_rec)); 2072de2362d3Smrg if (!flipdata) { 2073de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 2074de2362d3Smrg "flip queue: data alloc failed.\n"); 2075de2362d3Smrg goto error_undo; 2076de2362d3Smrg } 2077de2362d3Smrg /* 2078de2362d3Smrg * Queue flips on all enabled CRTCs 2079de2362d3Smrg * Note that if/when we get per-CRTC buffers, we'll have to update this. 2080de2362d3Smrg * Right now it assumes a single shared fb across all CRTCs, with the 2081de2362d3Smrg * kernel fixing up the offset of each CRTC as necessary. 2082de2362d3Smrg * 2083de2362d3Smrg * Also, flips queued on disabled or incorrectly configured displays 2084de2362d3Smrg * may never complete; this is a configuration error. 2085de2362d3Smrg */ 2086de2362d3Smrg 2087de2362d3Smrg flipdata->event_data = data; 2088de2362d3Smrg flipdata->drmmode = drmmode; 2089de2362d3Smrg 2090de2362d3Smrg for (i = 0; i < config->num_crtc; i++) { 2091de2362d3Smrg if (!config->crtc[i]->enabled) 2092de2362d3Smrg continue; 2093de2362d3Smrg 2094de2362d3Smrg flipdata->flip_count++; 2095de2362d3Smrg drmmode_crtc = config->crtc[i]->driver_private; 2096de2362d3Smrg 2097de2362d3Smrg flipcarrier = calloc(1, sizeof(drmmode_flipevtcarrier_rec)); 2098de2362d3Smrg if (!flipcarrier) { 2099de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 2100de2362d3Smrg "flip queue: carrier alloc failed.\n"); 2101de2362d3Smrg if (emitted == 0) 2102de2362d3Smrg free(flipdata); 2103de2362d3Smrg goto error_undo; 2104de2362d3Smrg } 2105de2362d3Smrg 2106de2362d3Smrg /* Only the reference crtc will finally deliver its page flip 2107de2362d3Smrg * completion event. All other crtc's events will be discarded. 2108de2362d3Smrg */ 2109de2362d3Smrg flipcarrier->dispatch_me = (drmmode_crtc->hw_id == ref_crtc_hw_id); 2110de2362d3Smrg flipcarrier->flipdata = flipdata; 2111de2362d3Smrg 2112de2362d3Smrg if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 2113de2362d3Smrg drmmode->fb_id, DRM_MODE_PAGE_FLIP_EVENT, flipcarrier)) { 2114de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 2115de2362d3Smrg "flip queue failed: %s\n", strerror(errno)); 2116de2362d3Smrg free(flipcarrier); 2117de2362d3Smrg if (emitted == 0) 2118de2362d3Smrg free(flipdata); 2119de2362d3Smrg goto error_undo; 2120de2362d3Smrg } 2121de2362d3Smrg emitted++; 2122de2362d3Smrg } 2123de2362d3Smrg 2124de2362d3Smrg flipdata->old_fb_id = old_fb_id; 2125de2362d3Smrg return TRUE; 2126de2362d3Smrg 2127de2362d3Smrgerror_undo: 2128de2362d3Smrg drmModeRmFB(drmmode->fd, drmmode->fb_id); 2129de2362d3Smrg drmmode->fb_id = old_fb_id; 2130de2362d3Smrg 2131de2362d3Smrgerror_out: 2132de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", 2133de2362d3Smrg strerror(errno)); 2134de2362d3Smrg return FALSE; 2135de2362d3Smrg} 2136de2362d3Smrg 2137