drmmode_display.c revision 7821949a
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> 337821949aSmrg#ifdef XF86DRM_MODE 34de2362d3Smrg#include <sys/ioctl.h> 35de2362d3Smrg#include "micmap.h" 36de2362d3Smrg#include "xf86cmap.h" 37de2362d3Smrg#include "radeon.h" 38de2362d3Smrg#include "radeon_reg.h" 397821949aSmrg#include "radeon_drm.h" 407821949aSmrg#include "sarea.h" 41de2362d3Smrg 42de2362d3Smrg#include "drmmode_display.h" 43de2362d3Smrg 44de2362d3Smrg/* DPMS */ 45de2362d3Smrg#ifdef HAVE_XEXTPROTO_71 46de2362d3Smrg#include <X11/extensions/dpmsconst.h> 47de2362d3Smrg#else 48de2362d3Smrg#define DPMS_SERVER 49de2362d3Smrg#include <X11/extensions/dpms.h> 50de2362d3Smrg#endif 51de2362d3Smrg 52de2362d3Smrgstatic PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn, 53de2362d3Smrg int width, int height, 54de2362d3Smrg int depth, int bpp, 557821949aSmrg int pitch, int tiling, 56de2362d3Smrg struct radeon_bo *bo, struct radeon_surface *psurf) 57de2362d3Smrg{ 58de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 59de2362d3Smrg ScreenPtr pScreen = pScrn->pScreen; 60de2362d3Smrg PixmapPtr pixmap; 61de2362d3Smrg struct radeon_surface *surface; 62de2362d3Smrg 637821949aSmrg pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0); 64de2362d3Smrg if (!pixmap) 65de2362d3Smrg return NULL; 66de2362d3Smrg 677314432eSmrg if (!(*pScreen->ModifyPixmapHeader)(pixmap, width, height, 687314432eSmrg depth, bpp, pitch, NULL)) { 697821949aSmrg return NULL; 707314432eSmrg } 717314432eSmrg 727821949aSmrg exaMoveInPixmap(pixmap); 737821949aSmrg radeon_set_pixmap_bo(pixmap, bo); 74de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 75de2362d3Smrg surface = radeon_get_pixmap_surface(pixmap); 76de2362d3Smrg if (surface && psurf) 77de2362d3Smrg *surface = *psurf; 78de2362d3Smrg else if (surface) { 79de2362d3Smrg memset(surface, 0, sizeof(struct radeon_surface)); 80de2362d3Smrg surface->npix_x = width; 81de2362d3Smrg surface->npix_y = height; 82de2362d3Smrg surface->npix_z = 1; 83de2362d3Smrg surface->blk_w = 1; 84de2362d3Smrg surface->blk_h = 1; 85de2362d3Smrg surface->blk_d = 1; 86de2362d3Smrg surface->array_size = 1; 87de2362d3Smrg surface->last_level = 0; 88de2362d3Smrg surface->bpe = bpp / 8; 89de2362d3Smrg surface->nsamples = 1; 90de2362d3Smrg surface->flags = RADEON_SURF_SCANOUT; 91de2362d3Smrg surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); 92de2362d3Smrg surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR_ALIGNED, MODE); 93de2362d3Smrg if (tiling & RADEON_TILING_MICRO) { 94de2362d3Smrg surface->flags = RADEON_SURF_CLR(surface->flags, MODE); 95de2362d3Smrg surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE); 96de2362d3Smrg } 97de2362d3Smrg if (tiling & RADEON_TILING_MACRO) { 98de2362d3Smrg surface->flags = RADEON_SURF_CLR(surface->flags, MODE); 99de2362d3Smrg surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE); 100de2362d3Smrg } 101de2362d3Smrg if (radeon_surface_best(info->surf_man, surface)) { 1027821949aSmrg return NULL; 103de2362d3Smrg } 104de2362d3Smrg if (radeon_surface_init(info->surf_man, surface)) { 1057821949aSmrg return NULL; 106de2362d3Smrg } 107de2362d3Smrg } 108de2362d3Smrg } 109de2362d3Smrg 1107821949aSmrg return pixmap; 111de2362d3Smrg} 112de2362d3Smrg 113de2362d3Smrgstatic void drmmode_destroy_bo_pixmap(PixmapPtr pixmap) 114de2362d3Smrg{ 115de2362d3Smrg ScreenPtr pScreen = pixmap->drawable.pScreen; 116de2362d3Smrg 117de2362d3Smrg (*pScreen->DestroyPixmap)(pixmap); 118de2362d3Smrg} 119de2362d3Smrg 120de2362d3Smrgstatic void 121de2362d3Smrgdrmmode_ConvertFromKMode(ScrnInfoPtr scrn, 122de2362d3Smrg drmModeModeInfo *kmode, 123de2362d3Smrg DisplayModePtr mode) 124de2362d3Smrg{ 125de2362d3Smrg memset(mode, 0, sizeof(DisplayModeRec)); 126de2362d3Smrg mode->status = MODE_OK; 127de2362d3Smrg 128de2362d3Smrg mode->Clock = kmode->clock; 129de2362d3Smrg 130de2362d3Smrg mode->HDisplay = kmode->hdisplay; 131de2362d3Smrg mode->HSyncStart = kmode->hsync_start; 132de2362d3Smrg mode->HSyncEnd = kmode->hsync_end; 133de2362d3Smrg mode->HTotal = kmode->htotal; 134de2362d3Smrg mode->HSkew = kmode->hskew; 135de2362d3Smrg 136de2362d3Smrg mode->VDisplay = kmode->vdisplay; 137de2362d3Smrg mode->VSyncStart = kmode->vsync_start; 138de2362d3Smrg mode->VSyncEnd = kmode->vsync_end; 139de2362d3Smrg mode->VTotal = kmode->vtotal; 140de2362d3Smrg mode->VScan = kmode->vscan; 141de2362d3Smrg 142de2362d3Smrg mode->Flags = kmode->flags; //& FLAG_BITS; 143de2362d3Smrg mode->name = strdup(kmode->name); 144de2362d3Smrg 145de2362d3Smrg if (kmode->type & DRM_MODE_TYPE_DRIVER) 146de2362d3Smrg mode->type = M_T_DRIVER; 147de2362d3Smrg if (kmode->type & DRM_MODE_TYPE_PREFERRED) 148de2362d3Smrg mode->type |= M_T_PREFERRED; 149de2362d3Smrg xf86SetModeCrtc (mode, scrn->adjustFlags); 150de2362d3Smrg} 151de2362d3Smrg 152de2362d3Smrgstatic void 153de2362d3Smrgdrmmode_ConvertToKMode(ScrnInfoPtr scrn, 154de2362d3Smrg drmModeModeInfo *kmode, 155de2362d3Smrg DisplayModePtr mode) 156de2362d3Smrg{ 157de2362d3Smrg memset(kmode, 0, sizeof(*kmode)); 158de2362d3Smrg 159de2362d3Smrg kmode->clock = mode->Clock; 160de2362d3Smrg kmode->hdisplay = mode->HDisplay; 161de2362d3Smrg kmode->hsync_start = mode->HSyncStart; 162de2362d3Smrg kmode->hsync_end = mode->HSyncEnd; 163de2362d3Smrg kmode->htotal = mode->HTotal; 164de2362d3Smrg kmode->hskew = mode->HSkew; 165de2362d3Smrg 166de2362d3Smrg kmode->vdisplay = mode->VDisplay; 167de2362d3Smrg kmode->vsync_start = mode->VSyncStart; 168de2362d3Smrg kmode->vsync_end = mode->VSyncEnd; 169de2362d3Smrg kmode->vtotal = mode->VTotal; 170de2362d3Smrg kmode->vscan = mode->VScan; 171de2362d3Smrg 172de2362d3Smrg kmode->flags = mode->Flags; //& FLAG_BITS; 173de2362d3Smrg if (mode->name) 174de2362d3Smrg strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); 175de2362d3Smrg kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0; 176de2362d3Smrg 177de2362d3Smrg} 178de2362d3Smrg 179de2362d3Smrgstatic void 1807821949aSmrgdrmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) 181de2362d3Smrg{ 182de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1837821949aSmrg// drmmode_ptr drmmode = drmmode_crtc->drmmode; 1847314432eSmrg 185de2362d3Smrg drmmode_crtc->dpms_mode = mode; 1860d16fef4Smrg 1877821949aSmrg#if 0 1887821949aSmrg /* bonghits in the randr 1.2 - uses dpms to disable crtc - bad buzz */ 1897821949aSmrg if (mode == DPMSModeOff) { 1907821949aSmrg// drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 1917821949aSmrg// 0, 0, 0, NULL, 0, NULL); 1927821949aSmrg } 1937821949aSmrg#endif 194de2362d3Smrg} 195de2362d3Smrg 196de2362d3Smrgstatic PixmapPtr 197de2362d3Smrgcreate_pixmap_for_fbcon(drmmode_ptr drmmode, 198de2362d3Smrg ScrnInfoPtr pScrn, int fbcon_id) 199de2362d3Smrg{ 2007821949aSmrg PixmapPtr pixmap = NULL; 201de2362d3Smrg struct radeon_bo *bo; 202de2362d3Smrg drmModeFBPtr fbcon; 203de2362d3Smrg struct drm_gem_flink flink; 204de2362d3Smrg 205de2362d3Smrg fbcon = drmModeGetFB(drmmode->fd, fbcon_id); 206de2362d3Smrg if (fbcon == NULL) 207de2362d3Smrg return NULL; 208de2362d3Smrg 209de2362d3Smrg if (fbcon->depth != pScrn->depth || 210de2362d3Smrg fbcon->width != pScrn->virtualX || 211de2362d3Smrg fbcon->height != pScrn->virtualY) 212de2362d3Smrg goto out_free_fb; 213de2362d3Smrg 214de2362d3Smrg flink.handle = fbcon->handle; 215de2362d3Smrg if (ioctl(drmmode->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) { 216de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 217de2362d3Smrg "Couldn't flink fbcon handle\n"); 218de2362d3Smrg goto out_free_fb; 219de2362d3Smrg } 220de2362d3Smrg 221de2362d3Smrg bo = radeon_bo_open(drmmode->bufmgr, flink.name, 0, 0, 0, 0); 222de2362d3Smrg if (bo == NULL) { 223de2362d3Smrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 224de2362d3Smrg "Couldn't allocate bo for fbcon handle\n"); 225de2362d3Smrg goto out_free_fb; 226de2362d3Smrg } 227de2362d3Smrg 228de2362d3Smrg pixmap = drmmode_create_bo_pixmap(pScrn, fbcon->width, fbcon->height, 2297821949aSmrg fbcon->depth, fbcon->bpp, 2307821949aSmrg fbcon->pitch, 0, bo, NULL); 231de2362d3Smrg radeon_bo_unref(bo); 232de2362d3Smrgout_free_fb: 233de2362d3Smrg drmModeFreeFB(fbcon); 234de2362d3Smrg return pixmap; 235de2362d3Smrg} 236de2362d3Smrg 237de2362d3Smrgvoid drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 238de2362d3Smrg{ 239de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 240de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 241de2362d3Smrg PixmapPtr src, dst; 242de2362d3Smrg ScreenPtr pScreen = pScrn->pScreen; 243de2362d3Smrg int fbcon_id = 0; 244de2362d3Smrg int i; 2457821949aSmrg int pitch; 2467821949aSmrg uint32_t tiling_flags = 0; 2477821949aSmrg Bool ret; 2487821949aSmrg 2497821949aSmrg if (info->accelOn == FALSE) 2507821949aSmrg goto fallback; 251de2362d3Smrg 252de2362d3Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 253de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private; 254de2362d3Smrg 255de2362d3Smrg if (drmmode_crtc->mode_crtc->buffer_id) 256de2362d3Smrg fbcon_id = drmmode_crtc->mode_crtc->buffer_id; 257de2362d3Smrg } 258de2362d3Smrg 259de2362d3Smrg if (!fbcon_id) 2607821949aSmrg goto fallback; 261de2362d3Smrg 262de2362d3Smrg src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id); 263de2362d3Smrg if (!src) 2647821949aSmrg goto fallback; 2650d16fef4Smrg 2667821949aSmrg if (info->allowColorTiling) { 2677821949aSmrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 2687821949aSmrg if (info->allowColorTiling2D) { 2697821949aSmrg tiling_flags |= RADEON_TILING_MACRO; 2707821949aSmrg } else { 2717821949aSmrg tiling_flags |= RADEON_TILING_MICRO; 2727821949aSmrg } 2737821949aSmrg } else 2747821949aSmrg tiling_flags |= RADEON_TILING_MACRO; 2757821949aSmrg } 276de2362d3Smrg 2777821949aSmrg pitch = RADEON_ALIGN(pScrn->displayWidth, 2787821949aSmrg drmmode_get_pitch_align(pScrn, info->CurrentLayout.pixel_bytes, tiling_flags)) * 2797821949aSmrg info->CurrentLayout.pixel_bytes; 2807821949aSmrg 2817821949aSmrg dst = drmmode_create_bo_pixmap(pScrn, pScrn->virtualX, 2827821949aSmrg pScrn->virtualY, pScrn->depth, 2837821949aSmrg pScrn->bitsPerPixel, pitch, 2847821949aSmrg tiling_flags, info->front_bo, &info->front_surface); 2857821949aSmrg if (!dst) 2867821949aSmrg goto out_free_src; 2877821949aSmrg 2887821949aSmrg ret = info->accel_state->exa->PrepareCopy (src, dst, 2897821949aSmrg -1, -1, GXcopy, FB_ALLONES); 2907821949aSmrg if (!ret) 2917821949aSmrg goto out_free_src; 2927821949aSmrg info->accel_state->exa->Copy (dst, 0, 0, 0, 0, 2937821949aSmrg pScrn->virtualX, pScrn->virtualY); 2947821949aSmrg info->accel_state->exa->DoneCopy (dst); 295de2362d3Smrg radeon_cs_flush_indirect(pScrn); 296de2362d3Smrg 2977821949aSmrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 10 298de2362d3Smrg pScreen->canDoBGNoneRoot = TRUE; 2990d16fef4Smrg#endif 3007821949aSmrg drmmode_destroy_bo_pixmap(dst); 3017821949aSmrg out_free_src: 3027821949aSmrg drmmode_destroy_bo_pixmap(src); 3037821949aSmrg return; 3040d16fef4Smrg 3057821949aSmrgfallback: 3067821949aSmrg /* map and memset the bo */ 3077821949aSmrg if (radeon_bo_map(info->front_bo, 1)) 3087821949aSmrg return; 3090d16fef4Smrg 3107821949aSmrg memset(info->front_bo->ptr, 0x00, info->front_bo->size); 3117821949aSmrg radeon_bo_unmap(info->front_bo); 3120d16fef4Smrg} 3130d16fef4Smrg 314de2362d3Smrgstatic Bool 315de2362d3Smrgdrmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 316de2362d3Smrg Rotation rotation, int x, int y) 317de2362d3Smrg{ 318de2362d3Smrg ScrnInfoPtr pScrn = crtc->scrn; 319de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 320de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 321de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 322de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 323de2362d3Smrg int saved_x, saved_y; 324de2362d3Smrg Rotation saved_rotation; 325de2362d3Smrg DisplayModeRec saved_mode; 3267821949aSmrg uint32_t *output_ids; 327de2362d3Smrg int output_count = 0; 3287821949aSmrg Bool ret = TRUE; 329de2362d3Smrg int i; 330de2362d3Smrg int fb_id; 331de2362d3Smrg drmModeModeInfo kmode; 3327821949aSmrg int pitch; 3337821949aSmrg uint32_t tiling_flags = 0; 3347821949aSmrg int height; 3357821949aSmrg 3367821949aSmrg if (info->allowColorTiling) { 3377821949aSmrg if (info->ChipFamily >= CHIP_FAMILY_R600) 3387821949aSmrg tiling_flags |= RADEON_TILING_MICRO; 3397821949aSmrg else 3407821949aSmrg tiling_flags |= RADEON_TILING_MACRO; 3417821949aSmrg } 3427821949aSmrg 3437821949aSmrg pitch = RADEON_ALIGN(pScrn->displayWidth, drmmode_get_pitch_align(pScrn, info->CurrentLayout.pixel_bytes, tiling_flags)) * 3447821949aSmrg info->CurrentLayout.pixel_bytes; 3457821949aSmrg height = RADEON_ALIGN(pScrn->virtualY, drmmode_get_height_align(pScrn, tiling_flags)); 3467821949aSmrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 3477821949aSmrg pitch = info->front_surface.level[0].pitch_bytes; 3487821949aSmrg } 3497821949aSmrg 3507821949aSmrg if (drmmode->fb_id == 0) { 3517821949aSmrg ret = drmModeAddFB(drmmode->fd, 3527821949aSmrg pScrn->virtualX, height, 3537821949aSmrg pScrn->depth, pScrn->bitsPerPixel, 3547821949aSmrg pitch, 3557821949aSmrg info->front_bo->handle, 3567821949aSmrg &drmmode->fb_id); 3577821949aSmrg if (ret < 0) { 3587821949aSmrg ErrorF("failed to add fb\n"); 3597821949aSmrg return FALSE; 3607821949aSmrg } 3617821949aSmrg } 362de2362d3Smrg 363de2362d3Smrg saved_mode = crtc->mode; 364de2362d3Smrg saved_x = crtc->x; 365de2362d3Smrg saved_y = crtc->y; 366de2362d3Smrg saved_rotation = crtc->rotation; 367de2362d3Smrg 368de2362d3Smrg if (mode) { 369de2362d3Smrg crtc->mode = *mode; 370de2362d3Smrg crtc->x = x; 371de2362d3Smrg crtc->y = y; 372de2362d3Smrg crtc->rotation = rotation; 3737821949aSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,5,99,0,0) 3747821949aSmrg crtc->transformPresent = FALSE; 3757821949aSmrg#endif 3767821949aSmrg } 377de2362d3Smrg 3787821949aSmrg output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); 3797821949aSmrg if (!output_ids) { 3807821949aSmrg ret = FALSE; 3817821949aSmrg goto done; 3827821949aSmrg } 383de2362d3Smrg 3847821949aSmrg if (mode) { 385de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 386de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 387de2362d3Smrg drmmode_output_private_ptr drmmode_output; 388de2362d3Smrg 389de2362d3Smrg if (output->crtc != crtc) 390de2362d3Smrg continue; 391de2362d3Smrg 392de2362d3Smrg drmmode_output = output->driver_private; 393de2362d3Smrg output_ids[output_count] = drmmode_output->mode_output->connector_id; 394de2362d3Smrg output_count++; 395de2362d3Smrg } 396de2362d3Smrg 3977821949aSmrg if (!xf86CrtcRotate(crtc)) { 398de2362d3Smrg goto done; 3997821949aSmrg } 4007821949aSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,0,0,0) 401de2362d3Smrg crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, 402de2362d3Smrg crtc->gamma_blue, crtc->gamma_size); 4037821949aSmrg#endif 4047821949aSmrg 405de2362d3Smrg drmmode_ConvertToKMode(crtc->scrn, &kmode, mode); 406de2362d3Smrg 407de2362d3Smrg fb_id = drmmode->fb_id; 4087821949aSmrg if (drmmode_crtc->rotate_fb_id) { 4097821949aSmrg fb_id = drmmode_crtc->rotate_fb_id; 410de2362d3Smrg x = y = 0; 411de2362d3Smrg } 4127821949aSmrg ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 4137821949aSmrg fb_id, x, y, output_ids, output_count, &kmode); 4147821949aSmrg if (ret) 415de2362d3Smrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 4167821949aSmrg "failed to set mode: %s", strerror(-ret)); 4177821949aSmrg else 418de2362d3Smrg ret = TRUE; 419de2362d3Smrg 4207821949aSmrg if (crtc->scrn->pScreen) 4217821949aSmrg xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen); 422de2362d3Smrg /* go through all the outputs and force DPMS them back on? */ 423de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 424de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 425de2362d3Smrg 426de2362d3Smrg if (output->crtc != crtc) 427de2362d3Smrg continue; 428de2362d3Smrg 429de2362d3Smrg output->funcs->dpms(output, DPMSModeOn); 430de2362d3Smrg } 431de2362d3Smrg } 432de2362d3Smrg 4337821949aSmrg if (pScrn->pScreen && 4347821949aSmrg !xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) 4357821949aSmrg xf86_reload_cursors(pScrn->pScreen); 436de2362d3Smrg 437de2362d3Smrgdone: 438de2362d3Smrg if (!ret) { 439de2362d3Smrg crtc->x = saved_x; 440de2362d3Smrg crtc->y = saved_y; 441de2362d3Smrg crtc->rotation = saved_rotation; 442de2362d3Smrg crtc->mode = saved_mode; 4437314432eSmrg } 4447821949aSmrg#if defined(XF86_CRTC_VERSION) && XF86_CRTC_VERSION >= 3 4457821949aSmrg else 4467821949aSmrg crtc->active = TRUE; 4477821949aSmrg#endif 448de2362d3Smrg 449de2362d3Smrg return ret; 450de2362d3Smrg} 451de2362d3Smrg 452de2362d3Smrgstatic void 453de2362d3Smrgdrmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg) 454de2362d3Smrg{ 455de2362d3Smrg 456de2362d3Smrg} 457de2362d3Smrg 458de2362d3Smrgstatic void 459de2362d3Smrgdrmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y) 460de2362d3Smrg{ 461de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 462de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 463de2362d3Smrg 464de2362d3Smrg drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); 465de2362d3Smrg} 466de2362d3Smrg 467de2362d3Smrgstatic void 468de2362d3Smrgdrmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image) 469de2362d3Smrg{ 470de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 4717821949aSmrg int i; 472de2362d3Smrg uint32_t *ptr; 473de2362d3Smrg 474de2362d3Smrg /* cursor should be mapped already */ 475de2362d3Smrg ptr = (uint32_t *)(drmmode_crtc->cursor_bo->ptr); 476de2362d3Smrg 4777821949aSmrg for (i = 0; i < 64 * 64; i++) 4787821949aSmrg ptr[i] = cpu_to_le32(image[i]); 479de2362d3Smrg} 480de2362d3Smrg 481de2362d3Smrg 482de2362d3Smrgstatic void 483de2362d3Smrgdrmmode_hide_cursor (xf86CrtcPtr crtc) 484de2362d3Smrg{ 485de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 486de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 487de2362d3Smrg 4887821949aSmrg drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 64, 64); 489de2362d3Smrg 490de2362d3Smrg} 491de2362d3Smrg 492de2362d3Smrgstatic void 493de2362d3Smrgdrmmode_show_cursor (xf86CrtcPtr crtc) 494de2362d3Smrg{ 495de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 496de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 497de2362d3Smrg uint32_t handle = drmmode_crtc->cursor_bo->handle; 4987314432eSmrg 4997821949aSmrg drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, handle, 64, 64); 500de2362d3Smrg} 501de2362d3Smrg 502de2362d3Smrgstatic void * 503de2362d3Smrgdrmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 504de2362d3Smrg{ 5057821949aSmrg ScrnInfoPtr pScrn = crtc->scrn; 5067821949aSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 507de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 5087821949aSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 5097821949aSmrg int size; 5107821949aSmrg struct radeon_bo *rotate_bo; 5117821949aSmrg int ret; 5127821949aSmrg unsigned long rotate_pitch; 5137821949aSmrg int base_align; 514de2362d3Smrg 5157821949aSmrg /* rotation requires acceleration */ 5167821949aSmrg if (info->r600_shadow_fb) { 5177821949aSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 5187821949aSmrg "Rotation requires acceleration!\n"); 5197821949aSmrg return NULL; 5207821949aSmrg } 5217821949aSmrg 5227821949aSmrg rotate_pitch = 5237821949aSmrg RADEON_ALIGN(width, drmmode_get_pitch_align(crtc->scrn, drmmode->cpp, 0)) * drmmode->cpp; 5247821949aSmrg height = RADEON_ALIGN(height, drmmode_get_height_align(crtc->scrn, 0)); 5257821949aSmrg base_align = drmmode_get_base_align(crtc->scrn, drmmode->cpp, 0); 5267821949aSmrg size = RADEON_ALIGN(rotate_pitch * height, RADEON_GPU_PAGE_SIZE); 5277821949aSmrg 5287821949aSmrg rotate_bo = radeon_bo_open(drmmode->bufmgr, 0, size, base_align, RADEON_GEM_DOMAIN_VRAM, 0); 5297821949aSmrg if (rotate_bo == NULL) 5307821949aSmrg return NULL; 5317821949aSmrg 5327821949aSmrg radeon_bo_map(rotate_bo, 1); 5337821949aSmrg 5347821949aSmrg ret = drmModeAddFB(drmmode->fd, width, height, crtc->scrn->depth, 5357821949aSmrg crtc->scrn->bitsPerPixel, rotate_pitch, 5367821949aSmrg rotate_bo->handle, 5377821949aSmrg &drmmode_crtc->rotate_fb_id); 5387821949aSmrg if (ret) { 5397821949aSmrg ErrorF("failed to add rotate fb\n"); 5407821949aSmrg } 5417821949aSmrg 5427821949aSmrg drmmode_crtc->rotate_bo = rotate_bo; 5437821949aSmrg return drmmode_crtc->rotate_bo->ptr; 544de2362d3Smrg} 545de2362d3Smrg 546de2362d3Smrgstatic PixmapPtr 547de2362d3Smrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 548de2362d3Smrg{ 5497821949aSmrg ScrnInfoPtr pScrn = crtc->scrn; 550de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 5517821949aSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 5527821949aSmrg unsigned long rotate_pitch; 5537821949aSmrg PixmapPtr rotate_pixmap; 554de2362d3Smrg 5557821949aSmrg if (!data) 5567821949aSmrg data = drmmode_crtc_shadow_allocate (crtc, width, height); 557de2362d3Smrg 5587821949aSmrg rotate_pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, drmmode->cpp, 0)) * drmmode->cpp; 5597821949aSmrg 5607821949aSmrg rotate_pixmap = drmmode_create_bo_pixmap(pScrn, 5617821949aSmrg width, height, 5627821949aSmrg pScrn->depth, 5637821949aSmrg pScrn->bitsPerPixel, 5647821949aSmrg rotate_pitch, 5657821949aSmrg 0, drmmode_crtc->rotate_bo, NULL); 5667821949aSmrg if (rotate_pixmap == NULL) { 5677821949aSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 5687821949aSmrg "Couldn't allocate shadow pixmap for rotated CRTC\n"); 5697821949aSmrg } 5707821949aSmrg return rotate_pixmap; 571de2362d3Smrg 572de2362d3Smrg} 573de2362d3Smrg 574de2362d3Smrgstatic void 5757821949aSmrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) 576de2362d3Smrg{ 577de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 578de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 579de2362d3Smrg 5807821949aSmrg if (rotate_pixmap) 5817821949aSmrg drmmode_destroy_bo_pixmap(rotate_pixmap); 582de2362d3Smrg 5837821949aSmrg if (data) { 5847821949aSmrg drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id); 5857821949aSmrg drmmode_crtc->rotate_fb_id = 0; 5867821949aSmrg radeon_bo_unmap(drmmode_crtc->rotate_bo); 5877821949aSmrg radeon_bo_unref(drmmode_crtc->rotate_bo); 5887821949aSmrg drmmode_crtc->rotate_bo = NULL; 589de2362d3Smrg } 590de2362d3Smrg 5917821949aSmrg} 592de2362d3Smrg 5937821949aSmrgstatic void 5947821949aSmrgdrmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 5957821949aSmrg uint16_t *blue, int size) 5967821949aSmrg{ 5977821949aSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 5987821949aSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 5997314432eSmrg 6007821949aSmrg drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 6017821949aSmrg size, red, green, blue); 602de2362d3Smrg} 603de2362d3Smrg 6047821949aSmrgstatic const xf86CrtcFuncsRec drmmode_crtc_funcs = { 605de2362d3Smrg .dpms = drmmode_crtc_dpms, 606de2362d3Smrg .set_mode_major = drmmode_set_mode_major, 607de2362d3Smrg .set_cursor_colors = drmmode_set_cursor_colors, 608de2362d3Smrg .set_cursor_position = drmmode_set_cursor_position, 609de2362d3Smrg .show_cursor = drmmode_show_cursor, 610de2362d3Smrg .hide_cursor = drmmode_hide_cursor, 611de2362d3Smrg .load_cursor_argb = drmmode_load_cursor_argb, 612de2362d3Smrg 613de2362d3Smrg .gamma_set = drmmode_crtc_gamma_set, 614de2362d3Smrg .shadow_create = drmmode_crtc_shadow_create, 615de2362d3Smrg .shadow_allocate = drmmode_crtc_shadow_allocate, 616de2362d3Smrg .shadow_destroy = drmmode_crtc_shadow_destroy, 617de2362d3Smrg .destroy = NULL, /* XXX */ 618de2362d3Smrg}; 619de2362d3Smrg 620de2362d3Smrgint drmmode_get_crtc_id(xf86CrtcPtr crtc) 621de2362d3Smrg{ 622de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 623de2362d3Smrg return drmmode_crtc->hw_id; 624de2362d3Smrg} 625de2362d3Smrg 626de2362d3Smrgvoid drmmode_crtc_hw_id(xf86CrtcPtr crtc) 627de2362d3Smrg{ 628de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 629de2362d3Smrg ScrnInfoPtr pScrn = crtc->scrn; 630de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 631de2362d3Smrg struct drm_radeon_info ginfo; 632de2362d3Smrg int r; 633de2362d3Smrg uint32_t tmp; 634de2362d3Smrg 635de2362d3Smrg memset(&ginfo, 0, sizeof(ginfo)); 636de2362d3Smrg ginfo.request = 0x4; 637de2362d3Smrg tmp = drmmode_crtc->mode_crtc->crtc_id; 638de2362d3Smrg ginfo.value = (uintptr_t)&tmp; 6397821949aSmrg r = drmCommandWriteRead(info->dri->drmFD, DRM_RADEON_INFO, &ginfo, sizeof(ginfo)); 640de2362d3Smrg if (r) { 641de2362d3Smrg drmmode_crtc->hw_id = -1; 642de2362d3Smrg return; 643de2362d3Smrg } 644de2362d3Smrg drmmode_crtc->hw_id = tmp; 645de2362d3Smrg} 646de2362d3Smrg 6477821949aSmrgstatic void 6487821949aSmrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num) 649de2362d3Smrg{ 650de2362d3Smrg xf86CrtcPtr crtc; 651de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc; 652de2362d3Smrg 653de2362d3Smrg crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs); 654de2362d3Smrg if (crtc == NULL) 6557821949aSmrg return; 656de2362d3Smrg 657de2362d3Smrg drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); 6587821949aSmrg drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, drmmode->mode_res->crtcs[num]); 659de2362d3Smrg drmmode_crtc->drmmode = drmmode; 660de2362d3Smrg crtc->driver_private = drmmode_crtc; 661de2362d3Smrg drmmode_crtc_hw_id(crtc); 662de2362d3Smrg 6637821949aSmrg return; 664de2362d3Smrg} 665de2362d3Smrg 666de2362d3Smrgstatic xf86OutputStatus 667de2362d3Smrgdrmmode_output_detect(xf86OutputPtr output) 668de2362d3Smrg{ 669de2362d3Smrg /* go to the hw and retrieve a new output struct */ 670de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 671de2362d3Smrg drmmode_ptr drmmode = drmmode_output->drmmode; 672de2362d3Smrg xf86OutputStatus status; 673de2362d3Smrg drmModeFreeConnector(drmmode_output->mode_output); 674de2362d3Smrg 675de2362d3Smrg drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id); 676de2362d3Smrg 677de2362d3Smrg switch (drmmode_output->mode_output->connection) { 678de2362d3Smrg case DRM_MODE_CONNECTED: 679de2362d3Smrg status = XF86OutputStatusConnected; 680de2362d3Smrg break; 681de2362d3Smrg case DRM_MODE_DISCONNECTED: 682de2362d3Smrg status = XF86OutputStatusDisconnected; 683de2362d3Smrg break; 684de2362d3Smrg default: 685de2362d3Smrg case DRM_MODE_UNKNOWNCONNECTION: 686de2362d3Smrg status = XF86OutputStatusUnknown; 687de2362d3Smrg break; 688de2362d3Smrg } 689de2362d3Smrg return status; 690de2362d3Smrg} 691de2362d3Smrg 692de2362d3Smrgstatic Bool 693de2362d3Smrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) 694de2362d3Smrg{ 695de2362d3Smrg return MODE_OK; 696de2362d3Smrg} 697de2362d3Smrg 698de2362d3Smrgstatic DisplayModePtr 699de2362d3Smrgdrmmode_output_get_modes(xf86OutputPtr output) 700de2362d3Smrg{ 701de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 702de2362d3Smrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 703de2362d3Smrg drmmode_ptr drmmode = drmmode_output->drmmode; 704de2362d3Smrg int i; 705de2362d3Smrg DisplayModePtr Modes = NULL, Mode; 706de2362d3Smrg drmModePropertyPtr props; 707de2362d3Smrg xf86MonPtr mon = NULL; 708de2362d3Smrg 709de2362d3Smrg /* look for an EDID property */ 710de2362d3Smrg for (i = 0; i < koutput->count_props; i++) { 711de2362d3Smrg props = drmModeGetProperty(drmmode->fd, koutput->props[i]); 712de2362d3Smrg if (props && (props->flags & DRM_MODE_PROP_BLOB)) { 713de2362d3Smrg if (!strcmp(props->name, "EDID")) { 714de2362d3Smrg if (drmmode_output->edid_blob) 715de2362d3Smrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 716de2362d3Smrg drmmode_output->edid_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]); 717de2362d3Smrg } 718de2362d3Smrg drmModeFreeProperty(props); 7197821949aSmrg } 720de2362d3Smrg } 721de2362d3Smrg 722de2362d3Smrg if (drmmode_output->edid_blob) { 723de2362d3Smrg mon = xf86InterpretEDID(output->scrn->scrnIndex, 724de2362d3Smrg drmmode_output->edid_blob->data); 725de2362d3Smrg if (mon && drmmode_output->edid_blob->length > 128) 726de2362d3Smrg mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 727de2362d3Smrg } 728de2362d3Smrg xf86OutputSetEDID(output, mon); 729de2362d3Smrg 730de2362d3Smrg /* modes should already be available */ 731de2362d3Smrg for (i = 0; i < koutput->count_modes; i++) { 732de2362d3Smrg Mode = xnfalloc(sizeof(DisplayModeRec)); 733de2362d3Smrg 734de2362d3Smrg drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode); 735de2362d3Smrg Modes = xf86ModesAdd(Modes, Mode); 736de2362d3Smrg 737de2362d3Smrg } 738de2362d3Smrg return Modes; 739de2362d3Smrg} 740de2362d3Smrg 741de2362d3Smrgstatic void 742de2362d3Smrgdrmmode_output_destroy(xf86OutputPtr output) 743de2362d3Smrg{ 744de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 745de2362d3Smrg int i; 746de2362d3Smrg 747de2362d3Smrg if (drmmode_output->edid_blob) 748de2362d3Smrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 749de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 750de2362d3Smrg drmModeFreeProperty(drmmode_output->props[i].mode_prop); 751de2362d3Smrg free(drmmode_output->props[i].atoms); 752de2362d3Smrg } 753de2362d3Smrg for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) { 754de2362d3Smrg drmModeFreeEncoder(drmmode_output->mode_encoders[i]); 7557821949aSmrg free(drmmode_output->mode_encoders); 756de2362d3Smrg } 757de2362d3Smrg free(drmmode_output->props); 758de2362d3Smrg drmModeFreeConnector(drmmode_output->mode_output); 759de2362d3Smrg free(drmmode_output); 760de2362d3Smrg output->driver_private = NULL; 761de2362d3Smrg} 762de2362d3Smrg 763de2362d3Smrgstatic void 764de2362d3Smrgdrmmode_output_dpms(xf86OutputPtr output, int mode) 765de2362d3Smrg{ 766de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 767de2362d3Smrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 768de2362d3Smrg drmmode_ptr drmmode = drmmode_output->drmmode; 769de2362d3Smrg 770de2362d3Smrg drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id, 771de2362d3Smrg drmmode_output->dpms_enum_id, mode); 7727821949aSmrg return; 773de2362d3Smrg} 774de2362d3Smrg 775de2362d3Smrg 776de2362d3Smrgstatic Bool 777de2362d3Smrgdrmmode_property_ignore(drmModePropertyPtr prop) 778de2362d3Smrg{ 779de2362d3Smrg if (!prop) 780de2362d3Smrg return TRUE; 781de2362d3Smrg /* ignore blob prop */ 782de2362d3Smrg if (prop->flags & DRM_MODE_PROP_BLOB) 783de2362d3Smrg return TRUE; 784de2362d3Smrg /* ignore standard property */ 785de2362d3Smrg if (!strcmp(prop->name, "EDID") || 786de2362d3Smrg !strcmp(prop->name, "DPMS")) 787de2362d3Smrg return TRUE; 788de2362d3Smrg 789de2362d3Smrg return FALSE; 790de2362d3Smrg} 791de2362d3Smrg 792de2362d3Smrgstatic void 793de2362d3Smrgdrmmode_output_create_resources(xf86OutputPtr output) 794de2362d3Smrg{ 795de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 796de2362d3Smrg drmModeConnectorPtr mode_output = drmmode_output->mode_output; 797de2362d3Smrg drmmode_ptr drmmode = drmmode_output->drmmode; 798de2362d3Smrg drmModePropertyPtr drmmode_prop; 799de2362d3Smrg int i, j, err; 800de2362d3Smrg 801de2362d3Smrg drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec)); 802de2362d3Smrg if (!drmmode_output->props) 803de2362d3Smrg return; 804de2362d3Smrg 805de2362d3Smrg drmmode_output->num_props = 0; 806de2362d3Smrg for (i = 0, j = 0; i < mode_output->count_props; i++) { 807de2362d3Smrg drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]); 808de2362d3Smrg if (drmmode_property_ignore(drmmode_prop)) { 809de2362d3Smrg drmModeFreeProperty(drmmode_prop); 810de2362d3Smrg continue; 811de2362d3Smrg } 812de2362d3Smrg drmmode_output->props[j].mode_prop = drmmode_prop; 813de2362d3Smrg drmmode_output->props[j].value = mode_output->prop_values[i]; 814de2362d3Smrg drmmode_output->num_props++; 815de2362d3Smrg j++; 816de2362d3Smrg } 817de2362d3Smrg 818de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 819de2362d3Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 820de2362d3Smrg drmmode_prop = p->mode_prop; 821de2362d3Smrg 822de2362d3Smrg if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 823de2362d3Smrg INT32 range[2]; 824de2362d3Smrg INT32 value = p->value; 825de2362d3Smrg 826de2362d3Smrg p->num_atoms = 1; 827de2362d3Smrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 828de2362d3Smrg if (!p->atoms) 829de2362d3Smrg continue; 830de2362d3Smrg p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 831de2362d3Smrg range[0] = drmmode_prop->values[0]; 832de2362d3Smrg range[1] = drmmode_prop->values[1]; 833de2362d3Smrg err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 834de2362d3Smrg FALSE, TRUE, 835de2362d3Smrg drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 836de2362d3Smrg 2, range); 837de2362d3Smrg if (err != 0) { 838de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 839de2362d3Smrg "RRConfigureOutputProperty error, %d\n", err); 840de2362d3Smrg } 841de2362d3Smrg err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 842de2362d3Smrg XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, TRUE); 843de2362d3Smrg if (err != 0) { 844de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 845de2362d3Smrg "RRChangeOutputProperty error, %d\n", err); 846de2362d3Smrg } 847de2362d3Smrg } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 848de2362d3Smrg p->num_atoms = drmmode_prop->count_enums + 1; 849de2362d3Smrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 850de2362d3Smrg if (!p->atoms) 851de2362d3Smrg continue; 852de2362d3Smrg p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 853de2362d3Smrg for (j = 1; j <= drmmode_prop->count_enums; j++) { 854de2362d3Smrg struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; 855de2362d3Smrg p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); 856de2362d3Smrg } 857de2362d3Smrg err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 858de2362d3Smrg FALSE, FALSE, 859de2362d3Smrg drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 860de2362d3Smrg p->num_atoms - 1, (INT32 *)&p->atoms[1]); 861de2362d3Smrg if (err != 0) { 862de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 863de2362d3Smrg "RRConfigureOutputProperty error, %d\n", err); 864de2362d3Smrg } 865de2362d3Smrg for (j = 0; j < drmmode_prop->count_enums; j++) 866de2362d3Smrg if (drmmode_prop->enums[j].value == p->value) 867de2362d3Smrg break; 868de2362d3Smrg /* there's always a matching value */ 869de2362d3Smrg err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 870de2362d3Smrg XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE); 871de2362d3Smrg if (err != 0) { 872de2362d3Smrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 873de2362d3Smrg "RRChangeOutputProperty error, %d\n", err); 874de2362d3Smrg } 875de2362d3Smrg } 876de2362d3Smrg } 877de2362d3Smrg} 878de2362d3Smrg 879de2362d3Smrgstatic Bool 880de2362d3Smrgdrmmode_output_set_property(xf86OutputPtr output, Atom property, 881de2362d3Smrg RRPropertyValuePtr value) 882de2362d3Smrg{ 883de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 884de2362d3Smrg drmmode_ptr drmmode = drmmode_output->drmmode; 885de2362d3Smrg int i; 886de2362d3Smrg 887de2362d3Smrg for (i = 0; i < drmmode_output->num_props; i++) { 888de2362d3Smrg drmmode_prop_ptr p = &drmmode_output->props[i]; 889de2362d3Smrg 890de2362d3Smrg if (p->atoms[0] != property) 891de2362d3Smrg continue; 892de2362d3Smrg 893de2362d3Smrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 894de2362d3Smrg uint32_t val; 895de2362d3Smrg 896de2362d3Smrg if (value->type != XA_INTEGER || value->format != 32 || 897de2362d3Smrg value->size != 1) 898de2362d3Smrg return FALSE; 899de2362d3Smrg val = *(uint32_t *)value->data; 900de2362d3Smrg 901de2362d3Smrg drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, 902de2362d3Smrg p->mode_prop->prop_id, (uint64_t)val); 903de2362d3Smrg return TRUE; 904de2362d3Smrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 905de2362d3Smrg Atom atom; 906de2362d3Smrg const char *name; 907de2362d3Smrg int j; 908de2362d3Smrg 909de2362d3Smrg if (value->type != XA_ATOM || value->format != 32 || value->size != 1) 910de2362d3Smrg return FALSE; 911de2362d3Smrg memcpy(&atom, value->data, 4); 912de2362d3Smrg name = NameForAtom(atom); 913de2362d3Smrg 914de2362d3Smrg /* search for matching name string, then set its value down */ 915de2362d3Smrg for (j = 0; j < p->mode_prop->count_enums; j++) { 916de2362d3Smrg if (!strcmp(p->mode_prop->enums[j].name, name)) { 917de2362d3Smrg drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, 918de2362d3Smrg p->mode_prop->prop_id, p->mode_prop->enums[j].value); 919de2362d3Smrg return TRUE; 920de2362d3Smrg } 921de2362d3Smrg } 922de2362d3Smrg } 923de2362d3Smrg } 924de2362d3Smrg 925de2362d3Smrg return TRUE; 926de2362d3Smrg} 927de2362d3Smrg 928de2362d3Smrgstatic Bool 929de2362d3Smrgdrmmode_output_get_property(xf86OutputPtr output, Atom property) 930de2362d3Smrg{ 931de2362d3Smrg return TRUE; 932de2362d3Smrg} 933de2362d3Smrg 934de2362d3Smrgstatic const xf86OutputFuncsRec drmmode_output_funcs = { 935de2362d3Smrg .dpms = drmmode_output_dpms, 936de2362d3Smrg .create_resources = drmmode_output_create_resources, 9377821949aSmrg#ifdef RANDR_12_INTERFACE 938de2362d3Smrg .set_property = drmmode_output_set_property, 939de2362d3Smrg .get_property = drmmode_output_get_property, 9407821949aSmrg#endif 941de2362d3Smrg#if 0 942de2362d3Smrg 943de2362d3Smrg .save = drmmode_crt_save, 944de2362d3Smrg .restore = drmmode_crt_restore, 945de2362d3Smrg .mode_fixup = drmmode_crt_mode_fixup, 946de2362d3Smrg .prepare = drmmode_output_prepare, 947de2362d3Smrg .mode_set = drmmode_crt_mode_set, 948de2362d3Smrg .commit = drmmode_output_commit, 949de2362d3Smrg#endif 950de2362d3Smrg .detect = drmmode_output_detect, 951de2362d3Smrg .mode_valid = drmmode_output_mode_valid, 952de2362d3Smrg 953de2362d3Smrg .get_modes = drmmode_output_get_modes, 954de2362d3Smrg .destroy = drmmode_output_destroy 955de2362d3Smrg}; 956de2362d3Smrg 957de2362d3Smrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown, 958de2362d3Smrg SubPixelHorizontalRGB, 959de2362d3Smrg SubPixelHorizontalBGR, 960de2362d3Smrg SubPixelVerticalRGB, 961de2362d3Smrg SubPixelVerticalBGR, 962de2362d3Smrg SubPixelNone }; 963de2362d3Smrg 964de2362d3Smrgconst char *output_names[] = { "None", 965de2362d3Smrg "VGA", 966de2362d3Smrg "DVI", 967de2362d3Smrg "DVI", 968de2362d3Smrg "DVI", 969de2362d3Smrg "Composite", 970de2362d3Smrg "S-video", 971de2362d3Smrg "LVDS", 972de2362d3Smrg "CTV", 973de2362d3Smrg "DIN", 974de2362d3Smrg "DisplayPort", 975de2362d3Smrg "HDMI", 976de2362d3Smrg "HDMI", 977de2362d3Smrg "TV", 978de2362d3Smrg "eDP" 979de2362d3Smrg}; 980de2362d3Smrg 981de2362d3Smrgstatic void 9827821949aSmrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num, int *num_dvi, int *num_hdmi) 9830d16fef4Smrg{ 984de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 985de2362d3Smrg xf86OutputPtr output; 986de2362d3Smrg drmModeConnectorPtr koutput; 987de2362d3Smrg drmModeEncoderPtr *kencoders = NULL; 988de2362d3Smrg drmmode_output_private_ptr drmmode_output; 989de2362d3Smrg drmModePropertyPtr props; 990de2362d3Smrg char name[32]; 991de2362d3Smrg int i; 992de2362d3Smrg const char *s; 993de2362d3Smrg 9947821949aSmrg koutput = drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]); 995de2362d3Smrg if (!koutput) 9967821949aSmrg return; 997de2362d3Smrg 998de2362d3Smrg kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); 999de2362d3Smrg if (!kencoders) { 1000de2362d3Smrg goto out_free_encoders; 1001de2362d3Smrg } 1002de2362d3Smrg 1003de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) { 1004de2362d3Smrg kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]); 1005de2362d3Smrg if (!kencoders[i]) { 1006de2362d3Smrg goto out_free_encoders; 1007de2362d3Smrg } 1008de2362d3Smrg } 1009de2362d3Smrg 10107821949aSmrg /* need to do smart conversion here for compat with non-kms ATI driver */ 10117821949aSmrg if (koutput->connector_type_id == 1) { 10127821949aSmrg switch(koutput->connector_type) { 10137821949aSmrg case DRM_MODE_CONNECTOR_DVII: 10147821949aSmrg case DRM_MODE_CONNECTOR_DVID: 10157821949aSmrg case DRM_MODE_CONNECTOR_DVIA: 10167821949aSmrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi); 10177821949aSmrg (*num_dvi)++; 10187821949aSmrg break; 10197821949aSmrg case DRM_MODE_CONNECTOR_HDMIA: 10207821949aSmrg case DRM_MODE_CONNECTOR_HDMIB: 10217821949aSmrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi); 10227821949aSmrg (*num_hdmi)++; 10237821949aSmrg break; 10247821949aSmrg case DRM_MODE_CONNECTOR_VGA: 10257821949aSmrg case DRM_MODE_CONNECTOR_DisplayPort: 10267821949aSmrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 10277821949aSmrg break; 10287821949aSmrg default: 10297821949aSmrg snprintf(name, 32, "%s", output_names[koutput->connector_type]); 10307821949aSmrg break; 10317821949aSmrg } 10327821949aSmrg } else { 10337821949aSmrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 1034de2362d3Smrg } 1035de2362d3Smrg 1036de2362d3Smrg if (xf86IsEntityShared(pScrn->entityList[0])) { 1037de2362d3Smrg if ((s = xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) { 1038de2362d3Smrg if (!RADEONZaphodStringMatches(pScrn, s, name)) 1039de2362d3Smrg goto out_free_encoders; 1040de2362d3Smrg } else { 10417821949aSmrg if (info->IsPrimary && (num != 0)) 1042de2362d3Smrg goto out_free_encoders; 1043de2362d3Smrg else if (info->IsSecondary && (num != 1)) 1044de2362d3Smrg goto out_free_encoders; 1045de2362d3Smrg } 1046de2362d3Smrg } 1047de2362d3Smrg 1048de2362d3Smrg output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name); 1049de2362d3Smrg if (!output) { 1050de2362d3Smrg goto out_free_encoders; 1051de2362d3Smrg } 1052de2362d3Smrg 1053de2362d3Smrg drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); 1054de2362d3Smrg if (!drmmode_output) { 1055de2362d3Smrg xf86OutputDestroy(output); 1056de2362d3Smrg goto out_free_encoders; 1057de2362d3Smrg } 1058de2362d3Smrg 10597821949aSmrg drmmode_output->output_id = drmmode->mode_res->connectors[num]; 1060de2362d3Smrg drmmode_output->mode_output = koutput; 1061de2362d3Smrg drmmode_output->mode_encoders = kencoders; 1062de2362d3Smrg drmmode_output->drmmode = drmmode; 1063de2362d3Smrg output->mm_width = koutput->mmWidth; 1064de2362d3Smrg output->mm_height = koutput->mmHeight; 1065de2362d3Smrg 1066de2362d3Smrg output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 1067de2362d3Smrg output->interlaceAllowed = TRUE; 1068de2362d3Smrg output->doubleScanAllowed = TRUE; 1069de2362d3Smrg output->driver_private = drmmode_output; 1070de2362d3Smrg 1071de2362d3Smrg output->possible_crtcs = 0xffffffff; 1072de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) { 1073de2362d3Smrg output->possible_crtcs &= kencoders[i]->possible_crtcs; 1074de2362d3Smrg } 1075de2362d3Smrg /* work out the possible clones later */ 1076de2362d3Smrg output->possible_clones = 0; 1077de2362d3Smrg 1078de2362d3Smrg for (i = 0; i < koutput->count_props; i++) { 1079de2362d3Smrg props = drmModeGetProperty(drmmode->fd, koutput->props[i]); 1080de2362d3Smrg if (props && (props->flags & DRM_MODE_PROP_ENUM)) { 1081de2362d3Smrg if (!strcmp(props->name, "DPMS")) { 1082de2362d3Smrg drmmode_output->dpms_enum_id = koutput->props[i]; 1083de2362d3Smrg drmModeFreeProperty(props); 1084de2362d3Smrg break; 1085de2362d3Smrg } 1086de2362d3Smrg drmModeFreeProperty(props); 1087de2362d3Smrg } 1088de2362d3Smrg } 1089de2362d3Smrg 10907821949aSmrg return; 1091de2362d3Smrgout_free_encoders: 1092de2362d3Smrg if (kencoders){ 1093de2362d3Smrg for (i = 0; i < koutput->count_encoders; i++) 1094de2362d3Smrg drmModeFreeEncoder(kencoders[i]); 1095de2362d3Smrg free(kencoders); 1096de2362d3Smrg } 1097de2362d3Smrg drmModeFreeConnector(koutput); 10987821949aSmrg 1099de2362d3Smrg} 1100de2362d3Smrg 1101de2362d3Smrguint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output) 1102de2362d3Smrg{ 1103de2362d3Smrg drmmode_output_private_ptr drmmode_output = output->driver_private, clone_drmout; 1104de2362d3Smrg int i; 1105de2362d3Smrg xf86OutputPtr clone_output; 1106de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1107de2362d3Smrg int index_mask = 0; 1108de2362d3Smrg 1109de2362d3Smrg if (drmmode_output->enc_clone_mask == 0) 1110de2362d3Smrg return index_mask; 1111de2362d3Smrg 1112de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 1113de2362d3Smrg clone_output = xf86_config->output[i]; 1114de2362d3Smrg clone_drmout = clone_output->driver_private; 1115de2362d3Smrg if (output == clone_output) 1116de2362d3Smrg continue; 1117de2362d3Smrg 1118de2362d3Smrg if (clone_drmout->enc_mask == 0) 1119de2362d3Smrg continue; 1120de2362d3Smrg if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask) 1121de2362d3Smrg index_mask |= (1 << i); 1122de2362d3Smrg } 1123de2362d3Smrg return index_mask; 1124de2362d3Smrg} 1125de2362d3Smrg 1126de2362d3Smrg 1127de2362d3Smrgstatic void 11287821949aSmrgdrmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 1129de2362d3Smrg{ 1130de2362d3Smrg int i, j; 1131de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1132de2362d3Smrg 1133de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 1134de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 1135de2362d3Smrg drmmode_output_private_ptr drmmode_output; 1136de2362d3Smrg 1137de2362d3Smrg drmmode_output = output->driver_private; 1138de2362d3Smrg drmmode_output->enc_clone_mask = 0xff; 1139de2362d3Smrg /* and all the possible encoder clones for this output together */ 1140de2362d3Smrg for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) 1141de2362d3Smrg { 1142de2362d3Smrg int k; 11437821949aSmrg for (k = 0; k < drmmode->mode_res->count_encoders; k++) { 11447821949aSmrg if (drmmode->mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id) 1145de2362d3Smrg drmmode_output->enc_mask |= (1 << k); 1146de2362d3Smrg } 1147de2362d3Smrg 1148de2362d3Smrg drmmode_output->enc_clone_mask &= drmmode_output->mode_encoders[j]->possible_clones; 1149de2362d3Smrg } 1150de2362d3Smrg } 1151de2362d3Smrg 1152de2362d3Smrg for (i = 0; i < xf86_config->num_output; i++) { 1153de2362d3Smrg xf86OutputPtr output = xf86_config->output[i]; 1154de2362d3Smrg output->possible_clones = find_clones(scrn, output); 1155de2362d3Smrg } 1156de2362d3Smrg} 1157de2362d3Smrg 1158de2362d3Smrg/* returns height alignment in pixels */ 1159de2362d3Smrgint drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling) 1160de2362d3Smrg{ 1161de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 1162de2362d3Smrg int height_align = 1; 1163de2362d3Smrg 1164de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 1165de2362d3Smrg if (tiling & RADEON_TILING_MACRO) 1166de2362d3Smrg height_align = info->num_channels * 8; 1167de2362d3Smrg else if (tiling & RADEON_TILING_MICRO) 1168de2362d3Smrg height_align = 8; 1169de2362d3Smrg else 1170de2362d3Smrg height_align = 8; 1171de2362d3Smrg } else { 11727821949aSmrg if (tiling) 1173de2362d3Smrg height_align = 16; 1174de2362d3Smrg else 1175de2362d3Smrg height_align = 1; 1176de2362d3Smrg } 1177de2362d3Smrg return height_align; 1178de2362d3Smrg} 1179de2362d3Smrg 1180de2362d3Smrg/* returns pitch alignment in pixels */ 1181de2362d3Smrgint drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling) 1182de2362d3Smrg{ 1183de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 1184de2362d3Smrg int pitch_align = 1; 1185de2362d3Smrg 1186de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 1187de2362d3Smrg if (tiling & RADEON_TILING_MACRO) { 1188de2362d3Smrg /* general surface requirements */ 1189de2362d3Smrg pitch_align = MAX(info->num_banks, 1190de2362d3Smrg (((info->group_bytes / 8) / bpe) * info->num_banks)) * 8; 1191de2362d3Smrg /* further restrictions for scanout */ 1192de2362d3Smrg pitch_align = MAX(info->num_banks * 8, pitch_align); 1193de2362d3Smrg } else if (tiling & RADEON_TILING_MICRO) { 1194de2362d3Smrg /* general surface requirements */ 1195de2362d3Smrg pitch_align = MAX(8, (info->group_bytes / (8 * bpe))); 1196de2362d3Smrg /* further restrictions for scanout */ 1197de2362d3Smrg pitch_align = MAX(info->group_bytes / bpe, pitch_align); 1198de2362d3Smrg } else { 1199de2362d3Smrg if (info->have_tiling_info) 1200de2362d3Smrg /* linear aligned requirements */ 1201de2362d3Smrg pitch_align = MAX(64, info->group_bytes / bpe); 1202de2362d3Smrg else 1203de2362d3Smrg /* default to 512 elements if we don't know the real 1204de2362d3Smrg * group size otherwise the kernel may reject the CS 1205de2362d3Smrg * if the group sizes don't match as the pitch won't 1206de2362d3Smrg * be aligned properly. 1207de2362d3Smrg */ 1208de2362d3Smrg pitch_align = 512; 1209de2362d3Smrg } 1210de2362d3Smrg } else { 1211de2362d3Smrg /* general surface requirements */ 1212de2362d3Smrg if (tiling) 1213de2362d3Smrg pitch_align = 256 / bpe; 1214de2362d3Smrg else 1215de2362d3Smrg pitch_align = 64; 1216de2362d3Smrg } 1217de2362d3Smrg return pitch_align; 1218de2362d3Smrg} 1219de2362d3Smrg 1220de2362d3Smrg/* returns base alignment in bytes */ 1221de2362d3Smrgint drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling) 1222de2362d3Smrg{ 1223de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 1224de2362d3Smrg int pixel_align = drmmode_get_pitch_align(scrn, bpe, tiling); 1225de2362d3Smrg int height_align = drmmode_get_height_align(scrn, tiling); 1226de2362d3Smrg int base_align = RADEON_GPU_PAGE_SIZE; 1227de2362d3Smrg 1228de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 1229de2362d3Smrg if (tiling & RADEON_TILING_MACRO) 1230de2362d3Smrg base_align = MAX(info->num_banks * info->num_channels * 8 * 8 * bpe, 1231de2362d3Smrg pixel_align * bpe * height_align); 1232de2362d3Smrg else { 1233de2362d3Smrg if (info->have_tiling_info) 1234de2362d3Smrg base_align = info->group_bytes; 1235de2362d3Smrg else 1236de2362d3Smrg /* default to 512 if we don't know the real 1237de2362d3Smrg * group size otherwise the kernel may reject the CS 1238de2362d3Smrg * if the group sizes don't match as the base won't 1239de2362d3Smrg * be aligned properly. 1240de2362d3Smrg */ 1241de2362d3Smrg base_align = 512; 1242de2362d3Smrg } 1243de2362d3Smrg } 1244de2362d3Smrg return base_align; 1245de2362d3Smrg} 1246de2362d3Smrg 1247de2362d3Smrgstatic Bool 1248de2362d3Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) 1249de2362d3Smrg{ 1250de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1251de2362d3Smrg drmmode_crtc_private_ptr 1252de2362d3Smrg drmmode_crtc = xf86_config->crtc[0]->driver_private; 1253de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 1254de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 1255de2362d3Smrg struct radeon_bo *old_front = NULL; 12567821949aSmrg Bool ret; 1257de2362d3Smrg ScreenPtr screen = xf86ScrnToScreen(scrn); 1258de2362d3Smrg uint32_t old_fb_id; 1259de2362d3Smrg int i, pitch, old_width, old_height, old_pitch; 12607821949aSmrg int screen_size; 12617821949aSmrg int cpp = info->CurrentLayout.pixel_bytes; 1262de2362d3Smrg struct radeon_bo *front_bo; 1263de2362d3Smrg struct radeon_surface surface; 1264de2362d3Smrg struct radeon_surface *psurface; 1265de2362d3Smrg uint32_t tiling_flags = 0, base_align; 1266de2362d3Smrg PixmapPtr ppix = screen->GetScreenPixmap(screen); 1267de2362d3Smrg void *fb_shadow; 1268de2362d3Smrg 1269de2362d3Smrg if (scrn->virtualX == width && scrn->virtualY == height) 1270de2362d3Smrg return TRUE; 1271de2362d3Smrg 1272de2362d3Smrg front_bo = info->front_bo; 1273de2362d3Smrg radeon_cs_flush_indirect(scrn); 1274de2362d3Smrg 1275de2362d3Smrg if (front_bo) 1276de2362d3Smrg radeon_bo_wait(front_bo); 1277de2362d3Smrg 12787821949aSmrg if (info->allowColorTiling) { 1279de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 1280de2362d3Smrg if (info->allowColorTiling2D) { 1281de2362d3Smrg tiling_flags |= RADEON_TILING_MACRO; 1282de2362d3Smrg } else { 1283de2362d3Smrg tiling_flags |= RADEON_TILING_MICRO; 1284de2362d3Smrg } 1285de2362d3Smrg } else 1286de2362d3Smrg tiling_flags |= RADEON_TILING_MACRO; 1287de2362d3Smrg } 1288de2362d3Smrg 1289de2362d3Smrg pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(scrn, cpp, tiling_flags)) * cpp; 12907821949aSmrg height = RADEON_ALIGN(height, drmmode_get_height_align(scrn, tiling_flags)); 12917821949aSmrg screen_size = RADEON_ALIGN(pitch * height, RADEON_GPU_PAGE_SIZE); 1292de2362d3Smrg base_align = 4096; 1293de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) { 1294de2362d3Smrg memset(&surface, 0, sizeof(struct radeon_surface)); 1295de2362d3Smrg surface.npix_x = width; 1296de2362d3Smrg surface.npix_y = height; 1297de2362d3Smrg surface.npix_z = 1; 1298de2362d3Smrg surface.blk_w = 1; 1299de2362d3Smrg surface.blk_h = 1; 1300de2362d3Smrg surface.blk_d = 1; 1301de2362d3Smrg surface.array_size = 1; 1302de2362d3Smrg surface.last_level = 0; 1303de2362d3Smrg surface.bpe = cpp; 1304de2362d3Smrg surface.nsamples = 1; 1305de2362d3Smrg surface.flags = RADEON_SURF_SCANOUT; 1306de2362d3Smrg surface.flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); 1307de2362d3Smrg surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR_ALIGNED, MODE); 1308de2362d3Smrg if (tiling_flags & RADEON_TILING_MICRO) { 1309de2362d3Smrg surface.flags = RADEON_SURF_CLR(surface.flags, MODE); 1310de2362d3Smrg surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE); 1311de2362d3Smrg } 1312de2362d3Smrg if (tiling_flags & RADEON_TILING_MACRO) { 1313de2362d3Smrg surface.flags = RADEON_SURF_CLR(surface.flags, MODE); 1314de2362d3Smrg surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE); 1315de2362d3Smrg } 1316de2362d3Smrg if (radeon_surface_best(info->surf_man, &surface)) { 1317de2362d3Smrg return FALSE; 1318de2362d3Smrg } 1319de2362d3Smrg if (radeon_surface_init(info->surf_man, &surface)) { 1320de2362d3Smrg return FALSE; 1321de2362d3Smrg } 1322de2362d3Smrg screen_size = surface.bo_size; 1323de2362d3Smrg base_align = surface.bo_alignment; 1324de2362d3Smrg pitch = surface.level[0].pitch_bytes; 1325de2362d3Smrg tiling_flags = 0; 1326de2362d3Smrg switch (surface.level[0].mode) { 1327de2362d3Smrg case RADEON_SURF_MODE_2D: 1328de2362d3Smrg tiling_flags |= RADEON_TILING_MACRO; 1329de2362d3Smrg tiling_flags |= surface.bankw << RADEON_TILING_EG_BANKW_SHIFT; 1330de2362d3Smrg tiling_flags |= surface.bankh << RADEON_TILING_EG_BANKH_SHIFT; 1331de2362d3Smrg tiling_flags |= surface.mtilea << RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT; 13327821949aSmrg tiling_flags |= eg_tile_split(surface.tile_split) << RADEON_TILING_EG_TILE_SPLIT_SHIFT; 1333de2362d3Smrg break; 1334de2362d3Smrg case RADEON_SURF_MODE_1D: 1335de2362d3Smrg tiling_flags |= RADEON_TILING_MICRO; 1336de2362d3Smrg break; 1337de2362d3Smrg default: 1338de2362d3Smrg break; 1339de2362d3Smrg } 1340de2362d3Smrg info->front_surface = surface; 1341de2362d3Smrg } 1342de2362d3Smrg 1343de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_INFO, 1344de2362d3Smrg "Allocate new frame buffer %dx%d stride %d\n", 1345de2362d3Smrg width, height, pitch / cpp); 1346de2362d3Smrg 1347de2362d3Smrg old_width = scrn->virtualX; 1348de2362d3Smrg old_height = scrn->virtualY; 1349de2362d3Smrg old_pitch = scrn->displayWidth; 1350de2362d3Smrg old_fb_id = drmmode->fb_id; 1351de2362d3Smrg old_front = info->front_bo; 1352de2362d3Smrg 1353de2362d3Smrg scrn->virtualX = width; 1354de2362d3Smrg scrn->virtualY = height; 1355de2362d3Smrg scrn->displayWidth = pitch / cpp; 1356de2362d3Smrg 13577821949aSmrg info->front_bo = radeon_bo_open(info->bufmgr, 0, screen_size, base_align, RADEON_GEM_DOMAIN_VRAM, 0); 1358de2362d3Smrg if (!info->front_bo) 1359de2362d3Smrg goto fail; 1360de2362d3Smrg 1361de2362d3Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN 1362de2362d3Smrg switch (cpp) { 1363de2362d3Smrg case 4: 1364de2362d3Smrg tiling_flags |= RADEON_TILING_SWAP_32BIT; 1365de2362d3Smrg break; 1366de2362d3Smrg case 2: 1367de2362d3Smrg tiling_flags |= RADEON_TILING_SWAP_16BIT; 1368de2362d3Smrg break; 1369de2362d3Smrg } 1370de2362d3Smrg#endif 1371de2362d3Smrg if (tiling_flags) 1372de2362d3Smrg radeon_bo_set_tiling(info->front_bo, tiling_flags, pitch); 1373de2362d3Smrg 13747821949aSmrg ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth, 13757821949aSmrg scrn->bitsPerPixel, pitch, 13767821949aSmrg info->front_bo->handle, 13777821949aSmrg &drmmode->fb_id); 13787821949aSmrg if (ret) 13797821949aSmrg goto fail; 13807821949aSmrg 1381de2362d3Smrg if (!info->r600_shadow_fb) { 13827821949aSmrg radeon_set_pixmap_bo(ppix, info->front_bo); 1383de2362d3Smrg psurface = radeon_get_pixmap_surface(ppix); 1384de2362d3Smrg *psurface = info->front_surface; 1385de2362d3Smrg screen->ModifyPixmapHeader(ppix, 1386de2362d3Smrg width, height, -1, -1, pitch, NULL); 1387de2362d3Smrg } else { 1388de2362d3Smrg if (radeon_bo_map(info->front_bo, 1)) 1389de2362d3Smrg goto fail; 1390de2362d3Smrg fb_shadow = calloc(1, screen_size); 1391de2362d3Smrg if (fb_shadow == NULL) 1392de2362d3Smrg goto fail; 1393de2362d3Smrg free(info->fb_shadow); 1394de2362d3Smrg info->fb_shadow = fb_shadow; 1395de2362d3Smrg screen->ModifyPixmapHeader(ppix, 1396de2362d3Smrg width, height, -1, -1, pitch, 1397de2362d3Smrg info->fb_shadow); 1398de2362d3Smrg } 13997821949aSmrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,9,99,1,0) 14007821949aSmrg scrn->pixmapPrivate.ptr = ppix->devPrivate.ptr; 14017821949aSmrg#endif 14020d16fef4Smrg 1403de2362d3Smrg for (i = 0; i < xf86_config->num_crtc; i++) { 1404de2362d3Smrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 1405de2362d3Smrg 1406de2362d3Smrg if (!crtc->enabled) 1407de2362d3Smrg continue; 1408de2362d3Smrg 1409de2362d3Smrg drmmode_set_mode_major(crtc, &crtc->mode, 1410de2362d3Smrg crtc->rotation, crtc->x, crtc->y); 1411de2362d3Smrg } 1412de2362d3Smrg 1413de2362d3Smrg if (old_fb_id) 1414de2362d3Smrg drmModeRmFB(drmmode->fd, old_fb_id); 1415de2362d3Smrg if (old_front) 1416de2362d3Smrg radeon_bo_unref(old_front); 1417de2362d3Smrg 1418de2362d3Smrg radeon_kms_update_vram_limit(scrn, screen_size); 1419de2362d3Smrg return TRUE; 1420de2362d3Smrg 1421de2362d3Smrg fail: 1422de2362d3Smrg if (info->front_bo) 1423de2362d3Smrg radeon_bo_unref(info->front_bo); 1424de2362d3Smrg info->front_bo = old_front; 1425de2362d3Smrg scrn->virtualX = old_width; 1426de2362d3Smrg scrn->virtualY = old_height; 1427de2362d3Smrg scrn->displayWidth = old_pitch; 1428de2362d3Smrg drmmode->fb_id = old_fb_id; 1429de2362d3Smrg 1430de2362d3Smrg return FALSE; 1431de2362d3Smrg} 1432de2362d3Smrg 1433de2362d3Smrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { 1434de2362d3Smrg drmmode_xf86crtc_resize 1435de2362d3Smrg}; 1436de2362d3Smrg 1437de2362d3Smrgstatic void 14387821949aSmrgdrmmode_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec, 14397821949aSmrg unsigned int tv_usec, void *event_data) 1440de2362d3Smrg{ 14417821949aSmrg radeon_dri2_frame_event_handler(frame, tv_sec, tv_usec, event_data); 1442de2362d3Smrg} 1443de2362d3Smrg 1444de2362d3Smrgstatic void 14457821949aSmrgdrmmode_flip_handler(int fd, unsigned int frame, unsigned int tv_sec, 14467821949aSmrg unsigned int tv_usec, void *event_data) 1447de2362d3Smrg{ 14487821949aSmrg drmmode_flipevtcarrier_ptr flipcarrier = event_data; 14497821949aSmrg drmmode_flipdata_ptr flipdata = flipcarrier->flipdata; 14507821949aSmrg drmmode_ptr drmmode = flipdata->drmmode; 1451de2362d3Smrg 1452de2362d3Smrg /* Is this the event whose info shall be delivered to higher level? */ 14537821949aSmrg if (flipcarrier->dispatch_me) { 1454de2362d3Smrg /* Yes: Cache msc, ust for later delivery. */ 1455de2362d3Smrg flipdata->fe_frame = frame; 14567821949aSmrg flipdata->fe_tv_sec = tv_sec; 14577821949aSmrg flipdata->fe_tv_usec = tv_usec; 1458de2362d3Smrg } 14597821949aSmrg free(flipcarrier); 1460de2362d3Smrg 14617821949aSmrg /* Last crtc completed flip? */ 14627821949aSmrg flipdata->flip_count--; 14637821949aSmrg if (flipdata->flip_count > 0) 14647821949aSmrg return; 1465de2362d3Smrg 14667821949aSmrg /* Release framebuffer */ 14677821949aSmrg drmModeRmFB(drmmode->fd, flipdata->old_fb_id); 1468de2362d3Smrg 14697821949aSmrg if (flipdata->event_data == NULL) 14707821949aSmrg return; 14717821949aSmrg 14727821949aSmrg /* Deliver cached msc, ust from reference crtc to flip event handler */ 14737821949aSmrg radeon_dri2_flip_event_handler(flipdata->fe_frame, flipdata->fe_tv_sec, 14747821949aSmrg flipdata->fe_tv_usec, flipdata->event_data); 1475de2362d3Smrg 14767821949aSmrg free(flipdata); 1477de2362d3Smrg} 1478de2362d3Smrg 1479de2362d3Smrg 1480de2362d3Smrgstatic void 1481de2362d3Smrgdrm_wakeup_handler(pointer data, int err, pointer p) 1482de2362d3Smrg{ 1483de2362d3Smrg drmmode_ptr drmmode = data; 1484de2362d3Smrg fd_set *read_mask = p; 1485de2362d3Smrg 14867821949aSmrg if (err >= 0 && FD_ISSET(drmmode->fd, read_mask)) { 1487de2362d3Smrg drmHandleEvent(drmmode->fd, &drmmode->event_context); 1488de2362d3Smrg } 1489de2362d3Smrg} 1490de2362d3Smrg 1491de2362d3SmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) 1492de2362d3Smrg{ 14937821949aSmrg xf86CrtcConfigPtr xf86_config; 1494de2362d3Smrg int i, num_dvi = 0, num_hdmi = 0; 1495de2362d3Smrg 1496de2362d3Smrg xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); 14977821949aSmrg xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1498de2362d3Smrg 1499de2362d3Smrg drmmode->scrn = pScrn; 1500de2362d3Smrg drmmode->cpp = cpp; 15017821949aSmrg drmmode->mode_res = drmModeGetResources(drmmode->fd); 15027821949aSmrg if (!drmmode->mode_res) 1503de2362d3Smrg return FALSE; 1504de2362d3Smrg 15057821949aSmrg xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width, drmmode->mode_res->max_height); 15067821949aSmrg for (i = 0; i < drmmode->mode_res->count_crtcs; i++) 15077821949aSmrg if (!xf86IsEntityShared(pScrn->entityList[0]) || pScrn->confScreen->device->screen == i) 15087821949aSmrg drmmode_crtc_init(pScrn, drmmode, i); 1509de2362d3Smrg 15107821949aSmrg for (i = 0; i < drmmode->mode_res->count_connectors; i++) 15117821949aSmrg drmmode_output_init(pScrn, drmmode, i, &num_dvi, &num_hdmi); 1512de2362d3Smrg 1513de2362d3Smrg /* workout clones */ 15147821949aSmrg drmmode_clones_init(pScrn, drmmode); 1515de2362d3Smrg 1516de2362d3Smrg xf86InitialConfiguration(pScrn, TRUE); 1517de2362d3Smrg 1518de2362d3Smrg drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION; 15197821949aSmrg drmmode->event_context.vblank_handler = drmmode_vblank_handler; 15207821949aSmrg drmmode->event_context.page_flip_handler = drmmode_flip_handler; 1521de2362d3Smrg 1522de2362d3Smrg return TRUE; 1523de2362d3Smrg} 1524de2362d3Smrg 1525de2362d3Smrgvoid drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 1526de2362d3Smrg{ 1527de2362d3Smrg RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 1528de2362d3Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 1529de2362d3Smrg 15307821949aSmrg if (pRADEONEnt->fd_wakeup_registered != serverGeneration && 15317821949aSmrg info->dri->pKernelDRMVersion->version_minor >= 4) { 1532de2362d3Smrg AddGeneralSocket(drmmode->fd); 1533de2362d3Smrg RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, 1534de2362d3Smrg drm_wakeup_handler, drmmode); 1535de2362d3Smrg pRADEONEnt->fd_wakeup_registered = serverGeneration; 1536de2362d3Smrg } 1537de2362d3Smrg} 1538de2362d3Smrg 1539de2362d3SmrgBool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, struct radeon_bo_manager *bufmgr) 1540de2362d3Smrg{ 1541de2362d3Smrg drmmode->bufmgr = bufmgr; 1542de2362d3Smrg return TRUE; 1543de2362d3Smrg} 1544de2362d3Smrg 1545de2362d3Smrg 1546de2362d3Smrg 1547de2362d3Smrgvoid drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id, struct radeon_bo *bo) 1548de2362d3Smrg{ 1549de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1550de2362d3Smrg xf86CrtcPtr crtc = xf86_config->crtc[id]; 1551de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1552de2362d3Smrg 1553de2362d3Smrg drmmode_crtc->cursor_bo = bo; 1554de2362d3Smrg} 1555de2362d3Smrg 1556de2362d3Smrgvoid drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y) 1557de2362d3Smrg{ 1558de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1559de2362d3Smrg xf86OutputPtr output = config->output[config->compat_output]; 1560de2362d3Smrg xf86CrtcPtr crtc = output->crtc; 1561de2362d3Smrg 1562de2362d3Smrg if (crtc && crtc->enabled) { 1563de2362d3Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 1564de2362d3Smrg x, y); 1565de2362d3Smrg } 1566de2362d3Smrg} 1567de2362d3Smrg 15687821949aSmrgBool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 1569de2362d3Smrg{ 1570de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1571de2362d3Smrg int c; 1572de2362d3Smrg 15737821949aSmrg drmmode_copy_fb(pScrn, drmmode); 15747821949aSmrg 1575de2362d3Smrg for (c = 0; c < config->num_crtc; c++) { 1576de2362d3Smrg xf86CrtcPtr crtc = config->crtc[c]; 1577de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1578de2362d3Smrg xf86OutputPtr output = NULL; 1579de2362d3Smrg int o; 1580de2362d3Smrg 1581de2362d3Smrg /* Skip disabled CRTCs */ 1582de2362d3Smrg if (!crtc->enabled) { 15837821949aSmrg drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 15847821949aSmrg 0, 0, 0, NULL, 0, NULL); 1585de2362d3Smrg continue; 1586de2362d3Smrg } 1587de2362d3Smrg 1588de2362d3Smrg if (config->output[config->compat_output]->crtc == crtc) 1589de2362d3Smrg output = config->output[config->compat_output]; 1590de2362d3Smrg else 1591de2362d3Smrg { 1592de2362d3Smrg for (o = 0; o < config->num_output; o++) 1593de2362d3Smrg if (config->output[o]->crtc == crtc) 1594de2362d3Smrg { 1595de2362d3Smrg output = config->output[o]; 1596de2362d3Smrg break; 1597de2362d3Smrg } 1598de2362d3Smrg } 1599de2362d3Smrg /* paranoia */ 1600de2362d3Smrg if (!output) 1601de2362d3Smrg continue; 1602de2362d3Smrg 1603de2362d3Smrg /* Mark that we'll need to re-set the mode for sure */ 1604de2362d3Smrg memset(&crtc->mode, 0, sizeof(crtc->mode)); 1605de2362d3Smrg if (!crtc->desiredMode.CrtcHDisplay) 1606de2362d3Smrg { 1607de2362d3Smrg DisplayModePtr mode = xf86OutputFindClosestMode (output, pScrn->currentMode); 1608de2362d3Smrg 1609de2362d3Smrg if (!mode) 1610de2362d3Smrg return FALSE; 1611de2362d3Smrg crtc->desiredMode = *mode; 1612de2362d3Smrg crtc->desiredRotation = RR_Rotate_0; 1613de2362d3Smrg crtc->desiredX = 0; 1614de2362d3Smrg crtc->desiredY = 0; 1615de2362d3Smrg } 1616de2362d3Smrg 16177821949aSmrg if (!crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, crtc->desiredRotation, 16187821949aSmrg crtc->desiredX, crtc->desiredY)) 16197821949aSmrg return FALSE; 1620de2362d3Smrg } 1621de2362d3Smrg return TRUE; 1622de2362d3Smrg} 1623de2362d3Smrg 16247821949aSmrgstatic void drmmode_load_palette(ScrnInfoPtr pScrn, int numColors, 16257821949aSmrg int *indices, LOCO *colors, VisualPtr pVisual) 1626de2362d3Smrg{ 1627de2362d3Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 16287821949aSmrg uint16_t lut_r[256], lut_g[256], lut_b[256]; 16297821949aSmrg int index, j, i; 16307821949aSmrg int c; 1631de2362d3Smrg 16327821949aSmrg for (c = 0; c < xf86_config->num_crtc; c++) { 16337821949aSmrg xf86CrtcPtr crtc = xf86_config->crtc[c]; 16347821949aSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 16357314432eSmrg 16367821949aSmrg for (i = 0 ; i < 256; i++) { 16377821949aSmrg lut_r[i] = drmmode_crtc->lut_r[i] << 6; 16387821949aSmrg lut_g[i] = drmmode_crtc->lut_g[i] << 6; 16397821949aSmrg lut_b[i] = drmmode_crtc->lut_b[i] << 6; 16407821949aSmrg } 16417314432eSmrg 16427821949aSmrg switch(pScrn->depth) { 16437821949aSmrg case 15: 16447821949aSmrg for (i = 0; i < numColors; i++) { 16457821949aSmrg index = indices[i]; 16467821949aSmrg for (j = 0; j < 8; j++) { 16477821949aSmrg lut_r[index * 8 + j] = colors[index].red << 6; 16487821949aSmrg lut_g[index * 8 + j] = colors[index].green << 6; 16497821949aSmrg lut_b[index * 8 + j] = colors[index].blue << 6; 16507821949aSmrg } 16517821949aSmrg } 16527821949aSmrg break; 16537821949aSmrg case 16: 16547821949aSmrg for (i = 0; i < numColors; i++) { 16557821949aSmrg index = indices[i]; 16567821949aSmrg 16577821949aSmrg if (i <= 31) { 16587821949aSmrg for (j = 0; j < 8; j++) { 16597821949aSmrg lut_r[index * 8 + j] = colors[index].red << 6; 16607821949aSmrg lut_b[index * 8 + j] = colors[index].blue << 6; 16617821949aSmrg } 16627821949aSmrg } 16637821949aSmrg 16647821949aSmrg for (j = 0; j < 4; j++) { 16657821949aSmrg lut_g[index * 4 + j] = colors[index].green << 6; 16667821949aSmrg } 16677821949aSmrg } 16687821949aSmrg break; 16697821949aSmrg default: 16707821949aSmrg for (i = 0; i < numColors; i++) { 16717821949aSmrg index = indices[i]; 16727821949aSmrg lut_r[index] = colors[index].red << 6; 16737821949aSmrg lut_g[index] = colors[index].green << 6; 16747821949aSmrg lut_b[index] = colors[index].blue << 6; 16757821949aSmrg } 16767821949aSmrg break; 16777821949aSmrg } 16787821949aSmrg 16797821949aSmrg /* Make the change through RandR */ 16807821949aSmrg#ifdef RANDR_12_INTERFACE 16817821949aSmrg if (crtc->randr_crtc) 16827821949aSmrg RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b); 16837821949aSmrg else 16847821949aSmrg#endif 16857821949aSmrg crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256); 16867821949aSmrg } 16877314432eSmrg} 16887314432eSmrg 16897821949aSmrgBool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn) 16900d16fef4Smrg{ 16917821949aSmrg xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 16927821949aSmrg "Initializing kms color map\n"); 16937821949aSmrg if (!miCreateDefColormap(pScreen)) 16947821949aSmrg return FALSE; 16957821949aSmrg /* all radeons support 10 bit CLUTs */ 16967821949aSmrg if (!xf86HandleColormaps(pScreen, 256, 10, 16977821949aSmrg drmmode_load_palette, NULL, 16987821949aSmrg CMAP_PALETTED_TRUECOLOR 16997821949aSmrg#if 0 /* This option messes up text mode! (eich@suse.de) */ 17007821949aSmrg | CMAP_LOAD_EVEN_IF_OFFSCREEN 17010d16fef4Smrg#endif 17027821949aSmrg | CMAP_RELOAD_ON_MODE_SWITCH)) 17037821949aSmrg return FALSE; 17047821949aSmrg return TRUE; 17050d16fef4Smrg} 17067821949aSmrg 1707de2362d3Smrg#ifdef HAVE_LIBUDEV 1708de2362d3Smrgstatic void 1709de2362d3Smrgdrmmode_handle_uevents(int fd, void *closure) 1710de2362d3Smrg{ 1711de2362d3Smrg drmmode_ptr drmmode = closure; 1712de2362d3Smrg ScrnInfoPtr scrn = drmmode->scrn; 1713de2362d3Smrg struct udev_device *dev; 17147821949aSmrg dev = udev_monitor_receive_device(drmmode->uevent_monitor); 17157821949aSmrg if (!dev) 17167821949aSmrg return; 17177314432eSmrg 17187821949aSmrg RRGetInfo(xf86ScrnToScreen(scrn), TRUE); 17197821949aSmrg udev_device_unref(dev); 1720de2362d3Smrg} 1721de2362d3Smrg#endif 1722de2362d3Smrg 1723de2362d3Smrgvoid drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 1724de2362d3Smrg{ 1725de2362d3Smrg#ifdef HAVE_LIBUDEV 1726de2362d3Smrg struct udev *u; 1727de2362d3Smrg struct udev_monitor *mon; 1728de2362d3Smrg 1729de2362d3Smrg u = udev_new(); 1730de2362d3Smrg if (!u) 1731de2362d3Smrg return; 1732de2362d3Smrg mon = udev_monitor_new_from_netlink(u, "udev"); 1733de2362d3Smrg if (!mon) { 1734de2362d3Smrg udev_unref(u); 1735de2362d3Smrg return; 1736de2362d3Smrg } 1737de2362d3Smrg 1738de2362d3Smrg if (udev_monitor_filter_add_match_subsystem_devtype(mon, 1739de2362d3Smrg "drm", 1740de2362d3Smrg "drm_minor") < 0 || 1741de2362d3Smrg udev_monitor_enable_receiving(mon) < 0) { 1742de2362d3Smrg udev_monitor_unref(mon); 1743de2362d3Smrg udev_unref(u); 1744de2362d3Smrg return; 1745de2362d3Smrg } 1746de2362d3Smrg 1747de2362d3Smrg drmmode->uevent_handler = 1748de2362d3Smrg xf86AddGeneralHandler(udev_monitor_get_fd(mon), 1749de2362d3Smrg drmmode_handle_uevents, 1750de2362d3Smrg drmmode); 1751de2362d3Smrg 1752de2362d3Smrg drmmode->uevent_monitor = mon; 1753de2362d3Smrg#endif 1754de2362d3Smrg} 1755de2362d3Smrg 1756de2362d3Smrgvoid drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) 1757de2362d3Smrg{ 1758de2362d3Smrg#ifdef HAVE_LIBUDEV 1759de2362d3Smrg if (drmmode->uevent_handler) { 1760de2362d3Smrg struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); 1761de2362d3Smrg xf86RemoveGeneralHandler(drmmode->uevent_handler); 1762de2362d3Smrg 1763de2362d3Smrg udev_monitor_unref(drmmode->uevent_monitor); 1764de2362d3Smrg udev_unref(u); 1765de2362d3Smrg } 1766de2362d3Smrg#endif 1767de2362d3Smrg} 1768de2362d3Smrg 17697821949aSmrgBool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data, int ref_crtc_hw_id) 1770de2362d3Smrg{ 1771de2362d3Smrg RADEONInfoPtr info = RADEONPTR(scrn); 1772de2362d3Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1773de2362d3Smrg drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; 1774de2362d3Smrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 1775de2362d3Smrg unsigned int pitch; 17767821949aSmrg int i, old_fb_id; 1777de2362d3Smrg uint32_t tiling_flags = 0; 17787821949aSmrg int height, emitted = 0; 1779de2362d3Smrg drmmode_flipdata_ptr flipdata; 17807821949aSmrg drmmode_flipevtcarrier_ptr flipcarrier; 1781de2362d3Smrg 1782de2362d3Smrg if (info->allowColorTiling) { 1783de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600) 1784de2362d3Smrg tiling_flags |= RADEON_TILING_MICRO; 1785de2362d3Smrg else 1786de2362d3Smrg tiling_flags |= RADEON_TILING_MACRO; 1787de2362d3Smrg } 1788de2362d3Smrg 17897821949aSmrg pitch = RADEON_ALIGN(scrn->displayWidth, drmmode_get_pitch_align(scrn, info->CurrentLayout.pixel_bytes, tiling_flags)) * 17907821949aSmrg info->CurrentLayout.pixel_bytes; 17917821949aSmrg height = RADEON_ALIGN(scrn->virtualY, drmmode_get_height_align(scrn, tiling_flags)); 1792de2362d3Smrg if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) { 1793de2362d3Smrg pitch = info->front_surface.level[0].pitch_bytes; 1794de2362d3Smrg } 1795de2362d3Smrg 17960d16fef4Smrg /* 17970d16fef4Smrg * Create a new handle for the back buffer 17980d16fef4Smrg */ 17997821949aSmrg old_fb_id = drmmode->fb_id; 18007821949aSmrg if (drmModeAddFB(drmmode->fd, scrn->virtualX, height, 18010d16fef4Smrg scrn->depth, scrn->bitsPerPixel, pitch, 18027821949aSmrg new_front->handle, &drmmode->fb_id)) 18037821949aSmrg goto error_out; 18040d16fef4Smrg 18057821949aSmrg flipdata = calloc(1, sizeof(drmmode_flipdata_rec)); 18067821949aSmrg if (!flipdata) { 18077821949aSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 18087821949aSmrg "flip queue: data alloc failed.\n"); 18097821949aSmrg goto error_undo; 18107821949aSmrg } 1811de2362d3Smrg /* 1812de2362d3Smrg * Queue flips on all enabled CRTCs 1813de2362d3Smrg * Note that if/when we get per-CRTC buffers, we'll have to update this. 1814de2362d3Smrg * Right now it assumes a single shared fb across all CRTCs, with the 1815de2362d3Smrg * kernel fixing up the offset of each CRTC as necessary. 1816de2362d3Smrg * 1817de2362d3Smrg * Also, flips queued on disabled or incorrectly configured displays 1818de2362d3Smrg * may never complete; this is a configuration error. 1819de2362d3Smrg */ 1820de2362d3Smrg 1821de2362d3Smrg flipdata->event_data = data; 18227821949aSmrg flipdata->drmmode = drmmode; 18237314432eSmrg 1824de2362d3Smrg for (i = 0; i < config->num_crtc; i++) { 18257821949aSmrg if (!config->crtc[i]->enabled) 1826de2362d3Smrg continue; 1827de2362d3Smrg 1828de2362d3Smrg flipdata->flip_count++; 18297821949aSmrg drmmode_crtc = config->crtc[i]->driver_private; 18307821949aSmrg 18317821949aSmrg flipcarrier = calloc(1, sizeof(drmmode_flipevtcarrier_rec)); 18327821949aSmrg if (!flipcarrier) { 18337821949aSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 18347821949aSmrg "flip queue: carrier alloc failed.\n"); 18357821949aSmrg if (emitted == 0) 18367821949aSmrg free(flipdata); 18377821949aSmrg goto error_undo; 18387821949aSmrg } 1839de2362d3Smrg 1840de2362d3Smrg /* Only the reference crtc will finally deliver its page flip 1841de2362d3Smrg * completion event. All other crtc's events will be discarded. 1842de2362d3Smrg */ 18437821949aSmrg flipcarrier->dispatch_me = (drmmode_crtc->hw_id == ref_crtc_hw_id); 18447821949aSmrg flipcarrier->flipdata = flipdata; 1845de2362d3Smrg 1846de2362d3Smrg if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 18477821949aSmrg drmmode->fb_id, DRM_MODE_PAGE_FLIP_EVENT, flipcarrier)) { 1848de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1849de2362d3Smrg "flip queue failed: %s\n", strerror(errno)); 18507821949aSmrg free(flipcarrier); 18517821949aSmrg if (emitted == 0) 18527821949aSmrg free(flipdata); 18537821949aSmrg goto error_undo; 1854de2362d3Smrg } 18557821949aSmrg emitted++; 1856de2362d3Smrg } 1857de2362d3Smrg 18587821949aSmrg flipdata->old_fb_id = old_fb_id; 18597821949aSmrg return TRUE; 18600d16fef4Smrg 18617821949aSmrgerror_undo: 18627821949aSmrg drmModeRmFB(drmmode->fd, drmmode->fb_id); 18637821949aSmrg drmmode->fb_id = old_fb_id; 1864de2362d3Smrg 18657821949aSmrgerror_out: 1866de2362d3Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", 1867de2362d3Smrg strerror(errno)); 1868de2362d3Smrg return FALSE; 1869de2362d3Smrg} 18707821949aSmrg 18717821949aSmrg#endif 1872