xf86-video-intel/src/drmmode_display.c

696 lines
18 KiB
C

/*
* Copyright © 2007 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Authors:
* Dave Airlie <airlied@redhat.com>
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef XF86DRM_MODE
#include "radeon.h"
#include "sarea.h"
static Bool drmmode_resize_fb(ScrnInfoPtr scrn, drmmode_ptr drmmode, int width, int height);
static Bool
drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[0]->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
Bool ret;
ErrorF("resize called %d %d\n", width, height);
ret = drmmode_resize_fb(scrn, drmmode, width, height);
scrn->virtualX = width;
scrn->virtualY = height;
return ret;
}
static void
drmmode_ConvertFromKMode(ScrnInfoPtr scrn,
struct drm_mode_modeinfo *kmode,
DisplayModePtr mode)
{
memset(mode, 0, sizeof(DisplayModeRec));
mode->status = MODE_OK;
mode->Clock = kmode->clock;
mode->HDisplay = kmode->hdisplay;
mode->HSyncStart = kmode->hsync_start;
mode->HSyncEnd = kmode->hsync_end;
mode->HTotal = kmode->htotal;
mode->HSkew = kmode->hskew;
mode->VDisplay = kmode->vdisplay;
mode->VSyncStart = kmode->vsync_start;
mode->VSyncEnd = kmode->vsync_end;
mode->VTotal = kmode->vtotal;
mode->VScan = kmode->vscan;
mode->Flags = kmode->flags; //& FLAG_BITS;
mode->name = strdup(kmode->name);
if (kmode->type & DRM_MODE_TYPE_DRIVER)
mode->type = M_T_DRIVER;
if (kmode->type & DRM_MODE_TYPE_PREFERRED)
mode->type |= M_T_PREFERRED;
xf86SetModeCrtc (mode, scrn->adjustFlags);
}
static void
drmmode_ConvertToKMode(ScrnInfoPtr scrn,
struct drm_mode_modeinfo *kmode,
DisplayModePtr mode)
{
memset(kmode, 0, sizeof(*kmode));
kmode->clock = mode->Clock;
kmode->hdisplay = mode->HDisplay;
kmode->hsync_start = mode->HSyncStart;
kmode->hsync_end = mode->HSyncEnd;
kmode->htotal = mode->HTotal;
kmode->hskew = mode->HSkew;
kmode->vdisplay = mode->VDisplay;
kmode->vsync_start = mode->VSyncStart;
kmode->vsync_end = mode->VSyncEnd;
kmode->vtotal = mode->VTotal;
kmode->vscan = mode->VScan;
kmode->flags = mode->Flags; //& FLAG_BITS;
if (mode->name)
strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
}
static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
drmmode_xf86crtc_resize
};
static void
drmmode_crtc_dpms(xf86CrtcPtr drmmode_crtc, int mode)
{
}
static Bool
drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
Rotation rotation, int x, int y)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
int saved_x, saved_y;
Rotation saved_rotation;
DisplayModeRec saved_mode;
uint32_t *output_ids;
int output_count = 0;
int ret = TRUE;
int i;
int fb_id;
struct drm_mode_modeinfo kmode;
saved_mode = crtc->mode;
saved_x = crtc->x;
saved_y = crtc->y;
saved_rotation = crtc->rotation;
crtc->mode = *mode;
crtc->x = x;
crtc->y = y;
crtc->rotation = rotation;
output_ids = xcalloc(sizeof(uint32_t), xf86_config->num_output);
if (!output_ids) {
ret = FALSE;
goto done;
}
for (i = 0; i < xf86_config->num_output; i++) {
xf86OutputPtr output = xf86_config->output[i];
drmmode_output_private_ptr drmmode_output;
if (output->crtc != crtc)
continue;
drmmode_output = output->driver_private;
output_ids[output_count] = drmmode_output->mode_output->connector_id;
output_count++;
}
if (!xf86CrtcRotate(crtc, mode, rotation)) {
goto done;
}
drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
fb_id = drmmode->fb_id;
if (drmmode_crtc->rotate_fb_id)
fb_id = drmmode_crtc->rotate_fb_id;
ErrorF("fb id is %d\n", fb_id);
drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
fb_id, x, y, output_ids, output_count, &kmode);
done:
if (!ret) {
crtc->x = saved_x;
crtc->y = saved_y;
crtc->rotation = saved_rotation;
crtc->mode = saved_mode;
}
return ret;
}
static void
drmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
{
}
static void
drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
{
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
}
static void
drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
{
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
int ret;
void *ptr;
/* cursor should be mapped already */
ptr = drmmode_crtc->cursor_map;
memcpy (ptr, image, 64 * 64 * 4);
return;
}
static void
drmmode_hide_cursor (xf86CrtcPtr crtc)
{
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 64, 64);
}
static void
drmmode_show_cursor (xf86CrtcPtr crtc)
{
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, drmmode_crtc->cursor_handle, 64, 64);
}
static void *
drmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
{
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
int ret;
int size;
unsigned long rotate_pitch;
rotate_pitch = crtc->scrn->displayWidth * drmmode->cpp;
size = rotate_pitch * height;
#if 0
drmmode_crtc->rotate_bo = dri_bo_alloc(drmmode->bufmgr, "rotate",
size, 4096, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_CACHED | DRM_BO_FLAG_CACHED_MAPPED);
if (!drmmode_crtc->rotate_bo) {
xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
"Couldn't allocate shadow memory for rotated CRTC\n");
return NULL;
}
dri_bo_map(drmmode_crtc->rotate_bo, 1);
ret = drmModeAddFB(drmmode->fd, width, height, crtc->scrn->depth,
crtc->scrn->bitsPerPixel, rotate_pitch, dri_bo_get_handle(drmmode_crtc->rotate_bo), &drmmode_crtc->rotate_fb_id);
if (ret) {
ErrorF("failed to add rotate fb\n");
}
return drmmode_crtc->rotate_bo->virtual;
#endif
return NULL;
}
static PixmapPtr
drmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
{
ScrnInfoPtr pScrn = crtc->scrn;
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
unsigned long rotate_pitch;
PixmapPtr rotate_pixmap;
if (!data)
data = drmmode_crtc_shadow_allocate (crtc, width, height);
rotate_pitch = pScrn->displayWidth * drmmode->cpp;
rotate_pixmap = GetScratchPixmapHeader(pScrn->pScreen,
width, height,
pScrn->depth,
pScrn->bitsPerPixel,
rotate_pitch,
data);
if (rotate_pixmap == NULL) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Couldn't allocate shadow pixmap for rotated CRTC\n");
}
return rotate_pixmap;
}
static void
drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
{
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
if (rotate_pixmap)
FreeScratchPixmapHeader(rotate_pixmap);
if (data) {
#if 0
/* Be sure to sync acceleration before the memory gets unbound. */
drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id);
drmmode_crtc->rotate_fb_id = 0;
dri_bo_unreference(drmmode_crtc->rotate_bo);
drmmode_crtc->rotate_bo = NULL;
#endif
}
}
static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
.dpms = drmmode_crtc_dpms,
.set_mode_major = drmmode_set_mode_major,
.set_cursor_colors = drmmode_set_cursor_colors,
.set_cursor_position = drmmode_set_cursor_position,
.show_cursor = drmmode_show_cursor,
.hide_cursor = drmmode_hide_cursor,
.load_cursor_argb = drmmode_load_cursor_argb,
.shadow_create = drmmode_crtc_shadow_create,
.shadow_allocate = drmmode_crtc_shadow_allocate,
.shadow_destroy = drmmode_crtc_shadow_destroy,
#if 0
.gamma_set = i830_crtc_gamma_set,
.shadow_create = i830_crtc_shadow_create,
.shadow_allocate = i830_crtc_shadow_allocate,
.shadow_destroy = i830_crtc_shadow_destroy,
.set_cursor_colors = i830_crtc_set_cursor_colors,
#endif
.destroy = NULL, /* XXX */
};
static void
drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
{
xf86CrtcPtr crtc;
drmmode_crtc_private_ptr drmmode_crtc;
int cursor_size = 64 * 64 * 4;
uint32_t mask;
int ret;
crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
if (crtc == NULL)
return;
drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, drmmode->mode_res->crtcs[num]);
drmmode_crtc->drmmode = drmmode;
crtc->driver_private = drmmode_crtc;
#if 0
drmmode_crtc->cursor_handle = drmmode->alloc_cursor(pScrn, num, 64, 64, &drmmode_crtc->cursor_map);
if (!drmmode_crtc->cursor_handle) {
ErrorF("failed to allocate cursor for crtc\n");
return;
}
#endif
return;
}
static xf86OutputStatus
drmmode_output_detect(xf86OutputPtr output)
{
/* go to the hw and retrieve a new output struct */
drmmode_output_private_ptr drmmode_output = output->driver_private;
drmmode_ptr drmmode = drmmode_output->drmmode;
xf86OutputStatus status;
drmModeFreeConnector(drmmode_output->mode_output);
drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
switch (drmmode_output->mode_output->connection) {
case DRM_MODE_CONNECTED:
status = XF86OutputStatusConnected;
break;
case DRM_MODE_DISCONNECTED:
status = XF86OutputStatusDisconnected;
break;
default:
case DRM_MODE_UNKNOWNCONNECTION:
status = XF86OutputStatusUnknown;
break;
}
return status;
}
static Bool
drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
{
return MODE_OK;
}
static DisplayModePtr
drmmode_output_get_modes(xf86OutputPtr output)
{
drmmode_output_private_ptr drmmode_output = output->driver_private;
drmModeConnectorPtr koutput = drmmode_output->mode_output;
drmmode_ptr drmmode = drmmode_output->drmmode;
int i;
DisplayModePtr Modes = NULL, Mode;
drmModePropertyPtr props;
/* look for an EDID property */
for (i = 0; i < koutput->count_props; i++) {
props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
if (!strcmp(props->name, "EDID")) {
if (drmmode_output->edid_blob)
drmModeFreePropertyBlob(drmmode_output->edid_blob);
drmmode_output->edid_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]);
}
drmModeFreeProperty(props);
}
}
if (drmmode_output->edid_blob)
xf86OutputSetEDID(output, xf86InterpretEDID(output->scrn->scrnIndex, drmmode_output->edid_blob->data));
else
xf86OutputSetEDID(output, xf86InterpretEDID(output->scrn->scrnIndex, NULL));
/* modes should already be available */
for (i = 0; i < koutput->count_modes; i++) {
Mode = xnfalloc(sizeof(DisplayModeRec));
drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode);
Modes = xf86ModesAdd(Modes, Mode);
}
return Modes;
}
static void
drmmode_output_destroy(xf86OutputPtr output)
{
drmmode_output_private_ptr drmmode_output = output->driver_private;
if (drmmode_output->edid_blob)
drmModeFreePropertyBlob(drmmode_output->edid_blob);
drmModeFreeConnector(drmmode_output->mode_output);
xfree(drmmode_output);
output->driver_private = NULL;
}
static void
drmmode_output_dpms(xf86OutputPtr output, int mode)
{
return;
}
static const xf86OutputFuncsRec drmmode_output_funcs = {
.dpms = drmmode_output_dpms,
#if 0
.save = drmmode_crt_save,
.restore = drmmode_crt_restore,
.mode_fixup = drmmode_crt_mode_fixup,
.prepare = drmmode_output_prepare,
.mode_set = drmmode_crt_mode_set,
.commit = drmmode_output_commit,
#endif
.detect = drmmode_output_detect,
.mode_valid = drmmode_output_mode_valid,
.get_modes = drmmode_output_get_modes,
.destroy = drmmode_output_destroy
};
static int subpixel_conv_table[7] = { 0, SubPixelUnknown,
SubPixelHorizontalRGB,
SubPixelHorizontalBGR,
SubPixelVerticalRGB,
SubPixelVerticalBGR,
SubPixelNone };
const char *output_names[] = { "None",
"VGA",
"DVI",
"DVI",
"DVI",
"Composite"
"TV",
"LVDS",
"CTV",
"DIN",
"DP",
"HDMI",
"HDMI",
};
static void
drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
{
xf86OutputPtr output;
drmModeConnectorPtr koutput;
drmModeEncoderPtr kencoder;
drmmode_output_private_ptr drmmode_output;
char name[32];
koutput = drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]);
if (!koutput)
return;
kencoder = drmModeGetEncoder(drmmode->fd, koutput->encoders[0]);
if (!kencoder) {
drmModeFreeConnector(koutput);
return;
}
snprintf(name, 32, "%s%d", output_names[koutput->connector_type], koutput->connector_type_id);
output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name);
if (!output) {
drmModeFreeEncoder(kencoder);
drmModeFreeConnector(koutput);
return;
}
drmmode_output = xcalloc(sizeof(drmmode_output_private_rec), 1);
if (!drmmode_output) {
xf86OutputDestroy(output);
drmModeFreeConnector(koutput);
drmModeFreeEncoder(kencoder);
return;
}
drmmode_output->output_id = drmmode->mode_res->connectors[num];
drmmode_output->mode_output = koutput;
drmmode_output->mode_encoder = kencoder;
drmmode_output->drmmode = drmmode;
output->mm_width = koutput->mmWidth;
output->mm_height = koutput->mmHeight;
output->subpixel_order = subpixel_conv_table[koutput->subpixel];
output->driver_private = drmmode_output;
output->possible_crtcs = kencoder->possible_crtcs;
output->possible_clones = kencoder->possible_clones;
return;
}
Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, char *busId, char *driver_name, int cpp)
{
xf86CrtcConfigPtr xf86_config;
int i;
Bool ret;
/* Create a bus Id */
/* Low level DRM open */
ret = DRIOpenDRMMaster(pScrn, SAREA_MAX, busId, driver_name);
if (!ret) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"[dri] DRIGetVersion failed to open the DRM\n"
"[dri] Disabling DRI.\n");
return FALSE;
}
drmmode->fd = DRIMasterFD(pScrn);
xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
drmmode->cpp = cpp;
drmmode->mode_res = drmModeGetResources(drmmode->fd);
if (!drmmode->mode_res)
return FALSE;
xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width, drmmode->mode_res->max_height);
for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
drmmode_crtc_init(pScrn, drmmode, i);
for (i = 0; i < drmmode->mode_res->count_connectors; i++)
drmmode_output_init(pScrn, drmmode, i);
xf86InitialConfiguration(pScrn, FALSE);
return TRUE;
}
#if 0
Bool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, dri_bufmgr *bufmgr)
{
drmmode->bufmgr = bufmgr;
return TRUE;
}
#endif
void drmmode_set_fb(ScrnInfoPtr scrn, drmmode_ptr drmmode, int width, int height, int pitch, uint32_t handle)
{
int ret;
ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth,
scrn->bitsPerPixel, pitch, handle, &drmmode->fb_id);
if (ret) {
ErrorF("Failed to add fb\n");
}
drmmode->mode_fb = drmModeGetFB(drmmode->fd, drmmode->fb_id);
if (!drmmode->mode_fb)
return;
ErrorF("Add fb id %d %d %d\n", drmmode->fb_id, width, height);
}
void drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id, void *ptr, uint32_t handle)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
xf86CrtcPtr crtc = xf86_config->crtc[id];
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_crtc->cursor_handle = handle;
drmmode_crtc->cursor_map = ptr;
}
#if 0
Bool drmmode_is_rotate_pixmap(ScrnInfoPtr pScrn, pointer pPixData, dri_bo **bo)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR (pScrn);
int i;
for (i = 0; i < config->num_crtc; i++) {
xf86CrtcPtr crtc = config->crtc[i];
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
if (!drmmode_crtc->rotate_bo)
continue;
if (drmmode_crtc->rotate_bo->virtual == pPixData) {
*bo = drmmode_crtc->rotate_bo;
return TRUE;
}
}
return FALSE;
}
#endif
static Bool drmmode_resize_fb(ScrnInfoPtr scrn, drmmode_ptr drmmode, int width, int height)
{
uint32_t handle;
int pitch;
int ret;
return FALSE;
if (drmmode->mode_fb->width == width && drmmode->mode_fb->height == height)
return TRUE;
if (!drmmode->create_new_fb)
return FALSE;
handle = drmmode->create_new_fb(scrn, width, height, &pitch);
if (handle == 0)
return FALSE;
ret = drmModeReplaceFB(drmmode->fd, drmmode->fb_id,
width, height,
scrn->depth, scrn->bitsPerPixel, pitch,
handle);
if (ret)
return FALSE;
drmModeFreeFB(drmmode->mode_fb);
drmmode->mode_fb = drmModeGetFB(drmmode->fd, drmmode->fb_id);
if (!drmmode->mode_fb)
return FALSE;
return TRUE;
}
#endif