/* * Copyright © 2009 Jerome Glisse * * This file is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include #include #include #include #include #include #include #include "xf86drm.h" #include "radeon_drm.h" #include "r600_winsys.h" #include "radeon.h" #include "radeon_bo.h" const char *connector_status(drmModeConnector *connector) { switch (connector->connection) { case DRM_MODE_CONNECTED: return "connected"; case DRM_MODE_DISCONNECTED: return "disconnected"; } return "unknown"; } int radeon_mode_configure(struct radeon *radeon) { struct radeon_mode *mode = &radeon->mode; drmModeRes *resources; drmModeConnector *connector; drmModeEncoder *encoder; u32 connector_id; int r; r = drmSetMaster(radeon->fd); if (r) { fprintf(stderr, "Failed to set master\n"); perror(NULL); } mode->bo = NULL; mode->fb_id = 0; resources = drmModeGetResources(radeon->fd); if (resources == NULL) { fprintf(stderr, "Failed to get resources from card\n"); return -EINVAL; } /* Iterates through connector an pick first one with a valid mode */ printf("%d connectors\n", resources->count_connectors); for (int i = 0; i < resources->count_connectors; i++) { connector = drmModeGetConnector(radeon->fd, resources->connectors[i]); if (connector == NULL) { fprintf(stderr, "Could not get connector %i\n", resources->connectors[i]); r = -EINVAL; goto out; } printf("connector(%d) %s to encoder(%d)\n", connector->connector_id, connector_status(connector), connector->encoder_id); for (int j = 0; j < connector->count_modes; j++) { if (connector->modes[j].type & DRM_MODE_TYPE_PREFERRED) { memcpy(&mode->info, &connector->modes[j], sizeof(drmModeModeInfo)); mode->connector_id = connector->connector_id; mode->encoder_id = connector->encoder_id; drmModeFreeConnector(connector); goto setmode; } } drmModeFreeConnector(connector); } fprintf(stderr, "No modes found !\n"); r = -EINVAL; goto out; setmode: /* Find crtc id */ encoder = drmModeGetEncoder(radeon->fd, mode->encoder_id); if (encoder == NULL) { fprintf(stderr, "Could not get encoder %i\n", mode->encoder_id); r = -EINVAL; goto out; } mode->crtc_id = resources->crtcs[ffs(encoder->possible_crtcs)-1]; drmModeFreeEncoder(encoder); /* Allocate buffer */ mode->bpp = 4; mode->height = mode->info.vdisplay; mode->pitch = mode->info.hdisplay * mode->bpp; mode->size = mode->pitch * mode->info.vdisplay; mode->bo = radeon_bo_open(radeon->bom, 0, mode->size, 0, RADEON_GEM_DOMAIN_VRAM, 0); if (mode->bo == NULL) { fprintf(stderr, "failed to create fb: %s\n", strerror(errno)); goto out; } r = drmModeAddFB(radeon->fd, mode->info.hdisplay, mode->info.vdisplay, 32, 32, mode->pitch, mode->bo->handle, &mode->fb_id); if (r) { fprintf(stderr, "failed to add fb: %s 0x%08X\n", strerror(errno), mode->bo->handle); goto out; } printf("Mode: %dx%d %dbpp on CRTC(%d) connector(%d)\n", mode->info.hdisplay, mode->info.vdisplay, mode->bpp*8, mode->crtc_id, mode->connector_id); connector_id = mode->connector_id; r = drmModeSetCrtc(radeon->fd, mode->crtc_id, mode->fb_id, 0, 0, &connector_id, 1, &mode->info); if (r) { fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); goto out; } if (connector_id != mode->connector_id) { fprintf(stderr, "Set mode on different connector %d, expected %d\n", connector_id, mode->connector_id); } out: if (r && mode->fb_id) { drmModeRmFB(radeon->fd, mode->fb_id); mode->fb_id = 0; } if (r && mode->bo) { mode->bo = radeon_bo_unref(mode->bo); } drmModeFreeResources(resources); return r; } void radeon_mode_cleanup(struct radeon *radeon) { if (radeon->mode.fb_id) { drmModeRmFB(radeon->fd, radeon->mode.fb_id); radeon->mode.fb_id = 0; } if (radeon->mode.bo) { radeon_bo_unmap(radeon->mode.bo); radeon->mode.bo = radeon_bo_unref(radeon->mode.bo); } drmDropMaster(radeon->fd); }