modetest.c revision a884aba1
118210155Smrg/* 218210155Smrg * DRM based mode setting test program 318210155Smrg * Copyright 2008 Tungsten Graphics 418210155Smrg * Jakob Bornecrantz <jakob@tungstengraphics.com> 518210155Smrg * Copyright 2008 Intel Corporation 618210155Smrg * Jesse Barnes <jesse.barnes@intel.com> 718210155Smrg * 818210155Smrg * Permission is hereby granted, free of charge, to any person obtaining a 918210155Smrg * copy of this software and associated documentation files (the "Software"), 1018210155Smrg * to deal in the Software without restriction, including without limitation 1118210155Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1218210155Smrg * and/or sell copies of the Software, and to permit persons to whom the 1318210155Smrg * Software is furnished to do so, subject to the following conditions: 1418210155Smrg * 1518210155Smrg * The above copyright notice and this permission notice shall be included in 1618210155Smrg * all copies or substantial portions of the Software. 1718210155Smrg * 1818210155Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1918210155Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2018210155Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2118210155Smrg * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2218210155Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2318210155Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2418210155Smrg * IN THE SOFTWARE. 2518210155Smrg */ 2618210155Smrg 2718210155Smrg/* 2818210155Smrg * This fairly simple test program dumps output in a similar format to the 2918210155Smrg * "xrandr" tool everyone knows & loves. It's necessarily slightly different 3018210155Smrg * since the kernel separates outputs into encoder and connector structures, 3118210155Smrg * each with their own unique ID. The program also allows test testing of the 3218210155Smrg * memory management and mode setting APIs by allowing the user to specify a 3318210155Smrg * connector and mode to use for mode setting. If all works as expected, a 3418210155Smrg * blue background should be painted on the monitor attached to the specified 3518210155Smrg * connector after the selected mode is set. 3618210155Smrg * 3718210155Smrg * TODO: use cairo to write the mode info on the selected output once 3818210155Smrg * the mode has been programmed, along with possible test patterns. 3918210155Smrg */ 40a884aba1Smrg#ifdef HAVE_CONFIG_H 4118210155Smrg#include "config.h" 42a884aba1Smrg#endif 4318210155Smrg 4418210155Smrg#include <assert.h> 45e88f27b3Smrg#include <ctype.h> 46e88f27b3Smrg#include <stdbool.h> 4718210155Smrg#include <stdio.h> 4818210155Smrg#include <stdlib.h> 4918210155Smrg#include <stdint.h> 50e88f27b3Smrg#include <inttypes.h> 5118210155Smrg#include <unistd.h> 5218210155Smrg#include <string.h> 5318210155Smrg#include <errno.h> 5422944501Smrg#include <sys/poll.h> 5522944501Smrg#include <sys/time.h> 5618210155Smrg 5718210155Smrg#include "xf86drm.h" 5818210155Smrg#include "xf86drmMode.h" 59e88f27b3Smrg#include "drm_fourcc.h" 60e88f27b3Smrg#include "libkms.h" 6118210155Smrg 62e88f27b3Smrg#include "buffers.h" 63a7d7de1eSmrg#include "cursor.h" 64e88f27b3Smrg 65e88f27b3Smrgstruct crtc { 66e88f27b3Smrg drmModeCrtc *crtc; 67e88f27b3Smrg drmModeObjectProperties *props; 68e88f27b3Smrg drmModePropertyRes **props_info; 69e88f27b3Smrg drmModeModeInfo *mode; 70e88f27b3Smrg}; 71e88f27b3Smrg 72e88f27b3Smrgstruct encoder { 73e88f27b3Smrg drmModeEncoder *encoder; 74e88f27b3Smrg}; 75e88f27b3Smrg 76e88f27b3Smrgstruct connector { 77e88f27b3Smrg drmModeConnector *connector; 78e88f27b3Smrg drmModeObjectProperties *props; 79e88f27b3Smrg drmModePropertyRes **props_info; 80e88f27b3Smrg}; 8118210155Smrg 82e88f27b3Smrgstruct fb { 83e88f27b3Smrg drmModeFB *fb; 84e88f27b3Smrg}; 85e88f27b3Smrg 86e88f27b3Smrgstruct plane { 87e88f27b3Smrg drmModePlane *plane; 88e88f27b3Smrg drmModeObjectProperties *props; 89e88f27b3Smrg drmModePropertyRes **props_info; 90e88f27b3Smrg}; 91e88f27b3Smrg 92e88f27b3Smrgstruct resources { 93e88f27b3Smrg drmModeRes *res; 94e88f27b3Smrg drmModePlaneRes *plane_res; 95e88f27b3Smrg 96e88f27b3Smrg struct crtc *crtcs; 97e88f27b3Smrg struct encoder *encoders; 98e88f27b3Smrg struct connector *connectors; 99e88f27b3Smrg struct fb *fbs; 100e88f27b3Smrg struct plane *planes; 101e88f27b3Smrg}; 102e88f27b3Smrg 103e88f27b3Smrgstruct device { 104e88f27b3Smrg int fd; 105e88f27b3Smrg 106e88f27b3Smrg struct resources *resources; 107e88f27b3Smrg struct kms_driver *kms; 108e88f27b3Smrg 109e88f27b3Smrg struct { 110e88f27b3Smrg unsigned int width; 111e88f27b3Smrg unsigned int height; 112e88f27b3Smrg 113e88f27b3Smrg unsigned int fb_id; 114e88f27b3Smrg struct kms_bo *bo; 115e88f27b3Smrg } mode; 116e88f27b3Smrg}; 11718210155Smrg 11818210155Smrg#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 11918210155Smrg 12018210155Smrgstruct type_name { 12118210155Smrg int type; 122e88f27b3Smrg const char *name; 12318210155Smrg}; 12418210155Smrg 12518210155Smrg#define type_name_fn(res) \ 126e88f27b3Smrgconst char * res##_str(int type) { \ 127e88f27b3Smrg unsigned int i; \ 12818210155Smrg for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \ 12918210155Smrg if (res##_names[i].type == type) \ 13018210155Smrg return res##_names[i].name; \ 13118210155Smrg } \ 13218210155Smrg return "(invalid)"; \ 13318210155Smrg} 13418210155Smrg 13518210155Smrgstruct type_name encoder_type_names[] = { 13618210155Smrg { DRM_MODE_ENCODER_NONE, "none" }, 13718210155Smrg { DRM_MODE_ENCODER_DAC, "DAC" }, 13818210155Smrg { DRM_MODE_ENCODER_TMDS, "TMDS" }, 13918210155Smrg { DRM_MODE_ENCODER_LVDS, "LVDS" }, 14018210155Smrg { DRM_MODE_ENCODER_TVDAC, "TVDAC" }, 14118210155Smrg}; 14218210155Smrg 143e88f27b3Smrgstatic type_name_fn(encoder_type) 14418210155Smrg 14518210155Smrgstruct type_name connector_status_names[] = { 14618210155Smrg { DRM_MODE_CONNECTED, "connected" }, 14718210155Smrg { DRM_MODE_DISCONNECTED, "disconnected" }, 14818210155Smrg { DRM_MODE_UNKNOWNCONNECTION, "unknown" }, 14918210155Smrg}; 15018210155Smrg 151e88f27b3Smrgstatic type_name_fn(connector_status) 15218210155Smrg 15318210155Smrgstruct type_name connector_type_names[] = { 15418210155Smrg { DRM_MODE_CONNECTOR_Unknown, "unknown" }, 15518210155Smrg { DRM_MODE_CONNECTOR_VGA, "VGA" }, 15618210155Smrg { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, 15718210155Smrg { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, 15818210155Smrg { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, 15918210155Smrg { DRM_MODE_CONNECTOR_Composite, "composite" }, 16018210155Smrg { DRM_MODE_CONNECTOR_SVIDEO, "s-video" }, 16118210155Smrg { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, 16218210155Smrg { DRM_MODE_CONNECTOR_Component, "component" }, 16318210155Smrg { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, 164e88f27b3Smrg { DRM_MODE_CONNECTOR_DisplayPort, "DP" }, 16518210155Smrg { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, 16618210155Smrg { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, 167d049871aSmrg { DRM_MODE_CONNECTOR_TV, "TV" }, 168e88f27b3Smrg { DRM_MODE_CONNECTOR_eDP, "eDP" }, 16918210155Smrg}; 17018210155Smrg 171e88f27b3Smrgstatic type_name_fn(connector_type) 172e88f27b3Smrg 173e88f27b3Smrg#define bit_name_fn(res) \ 174e88f27b3Smrgconst char * res##_str(int type) { \ 175e88f27b3Smrg unsigned int i; \ 176e88f27b3Smrg const char *sep = ""; \ 177e88f27b3Smrg for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \ 178e88f27b3Smrg if (type & (1 << i)) { \ 179e88f27b3Smrg printf("%s%s", sep, res##_names[i]); \ 180e88f27b3Smrg sep = ", "; \ 181e88f27b3Smrg } \ 182e88f27b3Smrg } \ 183e88f27b3Smrg return NULL; \ 184e88f27b3Smrg} 185e88f27b3Smrg 186e88f27b3Smrgstatic const char *mode_type_names[] = { 187e88f27b3Smrg "builtin", 188e88f27b3Smrg "clock_c", 189e88f27b3Smrg "crtc_c", 190e88f27b3Smrg "preferred", 191e88f27b3Smrg "default", 192e88f27b3Smrg "userdef", 193e88f27b3Smrg "driver", 194e88f27b3Smrg}; 195e88f27b3Smrg 196e88f27b3Smrgstatic bit_name_fn(mode_type) 197e88f27b3Smrg 198e88f27b3Smrgstatic const char *mode_flag_names[] = { 199e88f27b3Smrg "phsync", 200e88f27b3Smrg "nhsync", 201e88f27b3Smrg "pvsync", 202e88f27b3Smrg "nvsync", 203e88f27b3Smrg "interlace", 204e88f27b3Smrg "dblscan", 205e88f27b3Smrg "csync", 206e88f27b3Smrg "pcsync", 207e88f27b3Smrg "ncsync", 208e88f27b3Smrg "hskew", 209e88f27b3Smrg "bcast", 210e88f27b3Smrg "pixmux", 211e88f27b3Smrg "dblclk", 212e88f27b3Smrg "clkdiv2" 213e88f27b3Smrg}; 214e88f27b3Smrg 215e88f27b3Smrgstatic bit_name_fn(mode_flag) 21618210155Smrg 217e88f27b3Smrgstatic void dump_encoders(struct device *dev) 21818210155Smrg{ 21918210155Smrg drmModeEncoder *encoder; 22018210155Smrg int i; 22118210155Smrg 22218210155Smrg printf("Encoders:\n"); 22318210155Smrg printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n"); 224e88f27b3Smrg for (i = 0; i < dev->resources->res->count_encoders; i++) { 225e88f27b3Smrg encoder = dev->resources->encoders[i].encoder; 226e88f27b3Smrg if (!encoder) 22718210155Smrg continue; 228e88f27b3Smrg 22918210155Smrg printf("%d\t%d\t%s\t0x%08x\t0x%08x\n", 23018210155Smrg encoder->encoder_id, 23118210155Smrg encoder->crtc_id, 23218210155Smrg encoder_type_str(encoder->encoder_type), 23318210155Smrg encoder->possible_crtcs, 23418210155Smrg encoder->possible_clones); 23518210155Smrg } 23618210155Smrg printf("\n"); 23718210155Smrg} 23818210155Smrg 239e88f27b3Smrgstatic void dump_mode(drmModeModeInfo *mode) 24018210155Smrg{ 241e88f27b3Smrg printf(" %s %d %d %d %d %d %d %d %d %d", 24218210155Smrg mode->name, 24322944501Smrg mode->vrefresh, 24418210155Smrg mode->hdisplay, 24518210155Smrg mode->hsync_start, 24618210155Smrg mode->hsync_end, 24718210155Smrg mode->htotal, 24818210155Smrg mode->vdisplay, 24918210155Smrg mode->vsync_start, 25018210155Smrg mode->vsync_end, 25118210155Smrg mode->vtotal); 252e88f27b3Smrg 253e88f27b3Smrg printf(" flags: "); 254e88f27b3Smrg mode_flag_str(mode->flags); 255e88f27b3Smrg printf("; type: "); 256e88f27b3Smrg mode_type_str(mode->type); 257e88f27b3Smrg printf("\n"); 25818210155Smrg} 25918210155Smrg 260e88f27b3Smrgstatic void dump_blob(struct device *dev, uint32_t blob_id) 261e88f27b3Smrg{ 262e88f27b3Smrg uint32_t i; 263e88f27b3Smrg unsigned char *blob_data; 264e88f27b3Smrg drmModePropertyBlobPtr blob; 265e88f27b3Smrg 266e88f27b3Smrg blob = drmModeGetPropertyBlob(dev->fd, blob_id); 267e88f27b3Smrg if (!blob) 268e88f27b3Smrg return; 269e88f27b3Smrg 270e88f27b3Smrg blob_data = blob->data; 271e88f27b3Smrg 272e88f27b3Smrg for (i = 0; i < blob->length; i++) { 273e88f27b3Smrg if (i % 16 == 0) 274e88f27b3Smrg printf("\n\t\t\t"); 275e88f27b3Smrg printf("%.2hhx", blob_data[i]); 276e88f27b3Smrg } 277e88f27b3Smrg printf("\n"); 278e88f27b3Smrg 279e88f27b3Smrg drmModeFreePropertyBlob(blob); 280e88f27b3Smrg} 281e88f27b3Smrg 282e88f27b3Smrgstatic void dump_prop(struct device *dev, drmModePropertyPtr prop, 283e88f27b3Smrg uint32_t prop_id, uint64_t value) 28418210155Smrg{ 28518210155Smrg int i; 286e88f27b3Smrg printf("\t%d", prop_id); 287e88f27b3Smrg if (!prop) { 288e88f27b3Smrg printf("\n"); 289e88f27b3Smrg return; 290e88f27b3Smrg } 291e88f27b3Smrg 292e88f27b3Smrg printf(" %s:\n", prop->name); 293e88f27b3Smrg 294e88f27b3Smrg printf("\t\tflags:"); 295e88f27b3Smrg if (prop->flags & DRM_MODE_PROP_PENDING) 296e88f27b3Smrg printf(" pending"); 297e88f27b3Smrg if (prop->flags & DRM_MODE_PROP_RANGE) 298e88f27b3Smrg printf(" range"); 299e88f27b3Smrg if (prop->flags & DRM_MODE_PROP_IMMUTABLE) 300e88f27b3Smrg printf(" immutable"); 301e88f27b3Smrg if (prop->flags & DRM_MODE_PROP_ENUM) 302e88f27b3Smrg printf(" enum"); 303e88f27b3Smrg if (prop->flags & DRM_MODE_PROP_BITMASK) 304e88f27b3Smrg printf(" bitmask"); 305e88f27b3Smrg if (prop->flags & DRM_MODE_PROP_BLOB) 306e88f27b3Smrg printf(" blob"); 307e88f27b3Smrg printf("\n"); 308e88f27b3Smrg 309e88f27b3Smrg if (prop->flags & DRM_MODE_PROP_RANGE) { 310e88f27b3Smrg printf("\t\tvalues:"); 311e88f27b3Smrg for (i = 0; i < prop->count_values; i++) 312e88f27b3Smrg printf(" %"PRIu64, prop->values[i]); 313e88f27b3Smrg printf("\n"); 314e88f27b3Smrg } 31518210155Smrg 316e88f27b3Smrg if (prop->flags & DRM_MODE_PROP_ENUM) { 317e88f27b3Smrg printf("\t\tenums:"); 318e88f27b3Smrg for (i = 0; i < prop->count_enums; i++) 319e88f27b3Smrg printf(" %s=%llu", prop->enums[i].name, 320e88f27b3Smrg prop->enums[i].value); 321e88f27b3Smrg printf("\n"); 322e88f27b3Smrg } else if (prop->flags & DRM_MODE_PROP_BITMASK) { 323e88f27b3Smrg printf("\t\tvalues:"); 324e88f27b3Smrg for (i = 0; i < prop->count_enums; i++) 325e88f27b3Smrg printf(" %s=0x%llx", prop->enums[i].name, 326e88f27b3Smrg (1LL << prop->enums[i].value)); 327e88f27b3Smrg printf("\n"); 328e88f27b3Smrg } else { 329e88f27b3Smrg assert(prop->count_enums == 0); 330e88f27b3Smrg } 331e88f27b3Smrg 332e88f27b3Smrg if (prop->flags & DRM_MODE_PROP_BLOB) { 333e88f27b3Smrg printf("\t\tblobs:\n"); 334e88f27b3Smrg for (i = 0; i < prop->count_blobs; i++) 335e88f27b3Smrg dump_blob(dev, prop->blob_ids[i]); 336e88f27b3Smrg printf("\n"); 337e88f27b3Smrg } else { 338e88f27b3Smrg assert(prop->count_blobs == 0); 33918210155Smrg } 340e88f27b3Smrg 341e88f27b3Smrg printf("\t\tvalue:"); 342e88f27b3Smrg if (prop->flags & DRM_MODE_PROP_BLOB) 343e88f27b3Smrg dump_blob(dev, value); 344e88f27b3Smrg else 345e88f27b3Smrg printf(" %"PRIu64"\n", value); 34618210155Smrg} 34718210155Smrg 348e88f27b3Smrgstatic void dump_connectors(struct device *dev) 34918210155Smrg{ 35018210155Smrg int i, j; 35118210155Smrg 35218210155Smrg printf("Connectors:\n"); 35322944501Smrg printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\tencoders\n"); 354e88f27b3Smrg for (i = 0; i < dev->resources->res->count_connectors; i++) { 355e88f27b3Smrg struct connector *_connector = &dev->resources->connectors[i]; 356e88f27b3Smrg drmModeConnector *connector = _connector->connector; 357e88f27b3Smrg if (!connector) 35818210155Smrg continue; 35918210155Smrg 36022944501Smrg printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\t", 36118210155Smrg connector->connector_id, 36218210155Smrg connector->encoder_id, 36318210155Smrg connector_status_str(connector->connection), 36418210155Smrg connector_type_str(connector->connector_type), 36518210155Smrg connector->mmWidth, connector->mmHeight, 36618210155Smrg connector->count_modes); 36718210155Smrg 36822944501Smrg for (j = 0; j < connector->count_encoders; j++) 36922944501Smrg printf("%s%d", j > 0 ? ", " : "", connector->encoders[j]); 37022944501Smrg printf("\n"); 37122944501Smrg 372e88f27b3Smrg if (connector->count_modes) { 373e88f27b3Smrg printf(" modes:\n"); 374e88f27b3Smrg printf("\tname refresh (Hz) hdisp hss hse htot vdisp " 375e88f27b3Smrg "vss vse vtot)\n"); 376e88f27b3Smrg for (j = 0; j < connector->count_modes; j++) 377e88f27b3Smrg dump_mode(&connector->modes[j]); 378e88f27b3Smrg } 37922944501Smrg 380e88f27b3Smrg if (_connector->props) { 381e88f27b3Smrg printf(" props:\n"); 382e88f27b3Smrg for (j = 0; j < (int)_connector->props->count_props; j++) 383e88f27b3Smrg dump_prop(dev, _connector->props_info[j], 384e88f27b3Smrg _connector->props->props[j], 385e88f27b3Smrg _connector->props->prop_values[j]); 386e88f27b3Smrg } 38718210155Smrg } 38818210155Smrg printf("\n"); 38918210155Smrg} 39018210155Smrg 391e88f27b3Smrgstatic void dump_crtcs(struct device *dev) 39218210155Smrg{ 39318210155Smrg int i; 394e88f27b3Smrg uint32_t j; 39518210155Smrg 39618210155Smrg printf("CRTCs:\n"); 39718210155Smrg printf("id\tfb\tpos\tsize\n"); 398e88f27b3Smrg for (i = 0; i < dev->resources->res->count_crtcs; i++) { 399e88f27b3Smrg struct crtc *_crtc = &dev->resources->crtcs[i]; 400e88f27b3Smrg drmModeCrtc *crtc = _crtc->crtc; 401e88f27b3Smrg if (!crtc) 40218210155Smrg continue; 403e88f27b3Smrg 40418210155Smrg printf("%d\t%d\t(%d,%d)\t(%dx%d)\n", 40518210155Smrg crtc->crtc_id, 40618210155Smrg crtc->buffer_id, 40718210155Smrg crtc->x, crtc->y, 40818210155Smrg crtc->width, crtc->height); 40918210155Smrg dump_mode(&crtc->mode); 41018210155Smrg 411e88f27b3Smrg if (_crtc->props) { 412e88f27b3Smrg printf(" props:\n"); 413e88f27b3Smrg for (j = 0; j < _crtc->props->count_props; j++) 414e88f27b3Smrg dump_prop(dev, _crtc->props_info[j], 415e88f27b3Smrg _crtc->props->props[j], 416e88f27b3Smrg _crtc->props->prop_values[j]); 417e88f27b3Smrg } else { 418e88f27b3Smrg printf(" no properties found\n"); 419e88f27b3Smrg } 42018210155Smrg } 42118210155Smrg printf("\n"); 42218210155Smrg} 42318210155Smrg 424e88f27b3Smrgstatic void dump_framebuffers(struct device *dev) 42518210155Smrg{ 42618210155Smrg drmModeFB *fb; 42718210155Smrg int i; 42818210155Smrg 42918210155Smrg printf("Frame buffers:\n"); 43018210155Smrg printf("id\tsize\tpitch\n"); 431e88f27b3Smrg for (i = 0; i < dev->resources->res->count_fbs; i++) { 432e88f27b3Smrg fb = dev->resources->fbs[i].fb; 433e88f27b3Smrg if (!fb) 43418210155Smrg continue; 435e88f27b3Smrg 43622944501Smrg printf("%u\t(%ux%u)\t%u\n", 43718210155Smrg fb->fb_id, 43822944501Smrg fb->width, fb->height, 43922944501Smrg fb->pitch); 44018210155Smrg } 44118210155Smrg printf("\n"); 44218210155Smrg} 44318210155Smrg 444e88f27b3Smrgstatic void dump_planes(struct device *dev) 44518210155Smrg{ 446e88f27b3Smrg unsigned int i, j; 44718210155Smrg 448e88f27b3Smrg printf("Planes:\n"); 449e88f27b3Smrg printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\n"); 45018210155Smrg 451e88f27b3Smrg if (!dev->resources->plane_res) 452e88f27b3Smrg return; 45318210155Smrg 454e88f27b3Smrg for (i = 0; i < dev->resources->plane_res->count_planes; i++) { 455e88f27b3Smrg struct plane *plane = &dev->resources->planes[i]; 456e88f27b3Smrg drmModePlane *ovr = plane->plane; 457e88f27b3Smrg if (!ovr) 45818210155Smrg continue; 45918210155Smrg 460e88f27b3Smrg printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%-8d\t0x%08x\n", 461e88f27b3Smrg ovr->plane_id, ovr->crtc_id, ovr->fb_id, 462e88f27b3Smrg ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y, 463e88f27b3Smrg ovr->gamma_size, ovr->possible_crtcs); 464e88f27b3Smrg 465e88f27b3Smrg if (!ovr->count_formats) 46618210155Smrg continue; 46718210155Smrg 468e88f27b3Smrg printf(" formats:"); 469e88f27b3Smrg for (j = 0; j < ovr->count_formats; j++) 470e88f27b3Smrg printf(" %4.4s", (char *)&ovr->formats[j]); 471e88f27b3Smrg printf("\n"); 472e88f27b3Smrg 473e88f27b3Smrg if (plane->props) { 474e88f27b3Smrg printf(" props:\n"); 475e88f27b3Smrg for (j = 0; j < plane->props->count_props; j++) 476e88f27b3Smrg dump_prop(dev, plane->props_info[j], 477e88f27b3Smrg plane->props->props[j], 478e88f27b3Smrg plane->props->prop_values[j]); 479e88f27b3Smrg } else { 480e88f27b3Smrg printf(" no properties found\n"); 48118210155Smrg } 482e88f27b3Smrg } 483e88f27b3Smrg printf("\n"); 48418210155Smrg 485e88f27b3Smrg return; 486e88f27b3Smrg} 487e88f27b3Smrg 488e88f27b3Smrgstatic void free_resources(struct resources *res) 489e88f27b3Smrg{ 490e88f27b3Smrg if (!res) 491e88f27b3Smrg return; 49218210155Smrg 493e88f27b3Smrg#define free_resource(_res, __res, type, Type) \ 494e88f27b3Smrg do { \ 495e88f27b3Smrg int i; \ 496e88f27b3Smrg if (!(_res)->type##s) \ 497e88f27b3Smrg break; \ 498e88f27b3Smrg for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ 499e88f27b3Smrg if (!(_res)->type##s[i].type) \ 500e88f27b3Smrg break; \ 501e88f27b3Smrg drmModeFree##Type((_res)->type##s[i].type); \ 502e88f27b3Smrg } \ 503e88f27b3Smrg free((_res)->type##s); \ 504e88f27b3Smrg } while (0) 505e88f27b3Smrg 506e88f27b3Smrg#define free_properties(_res, __res, type) \ 507e88f27b3Smrg do { \ 508e88f27b3Smrg int i; \ 509e88f27b3Smrg for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ 510e88f27b3Smrg drmModeFreeObjectProperties(res->type##s[i].props); \ 511e88f27b3Smrg free(res->type##s[i].props_info); \ 512e88f27b3Smrg } \ 513e88f27b3Smrg } while (0) 514e88f27b3Smrg 515e88f27b3Smrg if (res->res) { 516e88f27b3Smrg free_properties(res, res, crtc); 517e88f27b3Smrg 518e88f27b3Smrg free_resource(res, res, crtc, Crtc); 519e88f27b3Smrg free_resource(res, res, encoder, Encoder); 520e88f27b3Smrg free_resource(res, res, connector, Connector); 521e88f27b3Smrg free_resource(res, res, fb, FB); 522e88f27b3Smrg 523e88f27b3Smrg drmModeFreeResources(res->res); 52418210155Smrg } 52518210155Smrg 526e88f27b3Smrg if (res->plane_res) { 527e88f27b3Smrg free_properties(res, plane_res, plane); 528e88f27b3Smrg 529e88f27b3Smrg free_resource(res, plane_res, plane, Plane); 530e88f27b3Smrg 531e88f27b3Smrg drmModeFreePlaneResources(res->plane_res); 53218210155Smrg } 53318210155Smrg 534e88f27b3Smrg free(res); 535e88f27b3Smrg} 53618210155Smrg 537e88f27b3Smrgstatic struct resources *get_resources(struct device *dev) 538e88f27b3Smrg{ 539e88f27b3Smrg struct resources *res; 540e88f27b3Smrg int i; 54118210155Smrg 542e88f27b3Smrg res = malloc(sizeof *res); 543e88f27b3Smrg if (res == 0) 544e88f27b3Smrg return NULL; 545e88f27b3Smrg 546e88f27b3Smrg memset(res, 0, sizeof *res); 547e88f27b3Smrg 548e88f27b3Smrg res->res = drmModeGetResources(dev->fd); 549e88f27b3Smrg if (!res->res) { 550e88f27b3Smrg fprintf(stderr, "drmModeGetResources failed: %s\n", 551e88f27b3Smrg strerror(errno)); 552e88f27b3Smrg goto error; 553e88f27b3Smrg } 55418210155Smrg 555e88f27b3Smrg res->crtcs = malloc(res->res->count_crtcs * sizeof *res->crtcs); 556e88f27b3Smrg res->encoders = malloc(res->res->count_encoders * sizeof *res->encoders); 557e88f27b3Smrg res->connectors = malloc(res->res->count_connectors * sizeof *res->connectors); 558e88f27b3Smrg res->fbs = malloc(res->res->count_fbs * sizeof *res->fbs); 559e88f27b3Smrg 560e88f27b3Smrg if (!res->crtcs || !res->encoders || !res->connectors || !res->fbs) 561e88f27b3Smrg goto error; 562e88f27b3Smrg 563e88f27b3Smrg memset(res->crtcs , 0, res->res->count_crtcs * sizeof *res->crtcs); 564e88f27b3Smrg memset(res->encoders, 0, res->res->count_encoders * sizeof *res->encoders); 565e88f27b3Smrg memset(res->connectors, 0, res->res->count_connectors * sizeof *res->connectors); 566e88f27b3Smrg memset(res->fbs, 0, res->res->count_fbs * sizeof *res->fbs); 567e88f27b3Smrg 568e88f27b3Smrg#define get_resource(_res, __res, type, Type) \ 569e88f27b3Smrg do { \ 570e88f27b3Smrg int i; \ 571e88f27b3Smrg for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ 572e88f27b3Smrg (_res)->type##s[i].type = \ 573e88f27b3Smrg drmModeGet##Type(dev->fd, (_res)->__res->type##s[i]); \ 574e88f27b3Smrg if (!(_res)->type##s[i].type) \ 575e88f27b3Smrg fprintf(stderr, "could not get %s %i: %s\n", \ 576e88f27b3Smrg #type, (_res)->__res->type##s[i], \ 577e88f27b3Smrg strerror(errno)); \ 578e88f27b3Smrg } \ 579e88f27b3Smrg } while (0) 580e88f27b3Smrg 581e88f27b3Smrg get_resource(res, res, crtc, Crtc); 582e88f27b3Smrg get_resource(res, res, encoder, Encoder); 583e88f27b3Smrg get_resource(res, res, connector, Connector); 584e88f27b3Smrg get_resource(res, res, fb, FB); 585e88f27b3Smrg 586e88f27b3Smrg#define get_properties(_res, __res, type, Type) \ 587e88f27b3Smrg do { \ 588e88f27b3Smrg int i; \ 589e88f27b3Smrg for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ 590e88f27b3Smrg struct type *obj = &res->type##s[i]; \ 591e88f27b3Smrg unsigned int j; \ 592e88f27b3Smrg obj->props = \ 593e88f27b3Smrg drmModeObjectGetProperties(dev->fd, obj->type->type##_id, \ 594e88f27b3Smrg DRM_MODE_OBJECT_##Type); \ 595e88f27b3Smrg if (!obj->props) { \ 596e88f27b3Smrg fprintf(stderr, \ 597e88f27b3Smrg "could not get %s %i properties: %s\n", \ 598e88f27b3Smrg #type, obj->type->type##_id, \ 599e88f27b3Smrg strerror(errno)); \ 600e88f27b3Smrg continue; \ 601e88f27b3Smrg } \ 602e88f27b3Smrg obj->props_info = malloc(obj->props->count_props * \ 603e88f27b3Smrg sizeof *obj->props_info); \ 604e88f27b3Smrg if (!obj->props_info) \ 605e88f27b3Smrg continue; \ 606e88f27b3Smrg for (j = 0; j < obj->props->count_props; ++j) \ 607e88f27b3Smrg obj->props_info[j] = \ 608e88f27b3Smrg drmModeGetProperty(dev->fd, obj->props->props[j]); \ 609e88f27b3Smrg } \ 610e88f27b3Smrg } while (0) 611e88f27b3Smrg 612e88f27b3Smrg get_properties(res, res, crtc, CRTC); 613e88f27b3Smrg get_properties(res, res, connector, CONNECTOR); 614e88f27b3Smrg 615e88f27b3Smrg for (i = 0; i < res->res->count_crtcs; ++i) 616e88f27b3Smrg res->crtcs[i].mode = &res->crtcs[i].crtc->mode; 617e88f27b3Smrg 618e88f27b3Smrg res->plane_res = drmModeGetPlaneResources(dev->fd); 619e88f27b3Smrg if (!res->plane_res) { 620e88f27b3Smrg fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", 621e88f27b3Smrg strerror(errno)); 622e88f27b3Smrg return res; 62318210155Smrg } 62418210155Smrg 625e88f27b3Smrg res->planes = malloc(res->plane_res->count_planes * sizeof *res->planes); 626e88f27b3Smrg if (!res->planes) 627e88f27b3Smrg goto error; 628e88f27b3Smrg 629e88f27b3Smrg memset(res->planes, 0, res->plane_res->count_planes * sizeof *res->planes); 630e88f27b3Smrg 631e88f27b3Smrg get_resource(res, plane_res, plane, Plane); 632e88f27b3Smrg get_properties(res, plane_res, plane, PLANE); 633e88f27b3Smrg 634e88f27b3Smrg return res; 635e88f27b3Smrg 636e88f27b3Smrgerror: 637e88f27b3Smrg free_resources(res); 638e88f27b3Smrg return NULL; 63918210155Smrg} 64018210155Smrg 641e88f27b3Smrgstatic int get_crtc_index(struct device *dev, uint32_t id) 642d049871aSmrg{ 643e88f27b3Smrg int i; 64418210155Smrg 645e88f27b3Smrg for (i = 0; i < dev->resources->res->count_crtcs; ++i) { 646e88f27b3Smrg drmModeCrtc *crtc = dev->resources->crtcs[i].crtc; 647e88f27b3Smrg if (crtc && crtc->crtc_id == id) 648e88f27b3Smrg return i; 649e88f27b3Smrg } 650d049871aSmrg 651e88f27b3Smrg return -1; 652d049871aSmrg} 653d049871aSmrg 654e88f27b3Smrgstatic drmModeConnector *get_connector_by_id(struct device *dev, uint32_t id) 65518210155Smrg{ 656e88f27b3Smrg drmModeConnector *connector; 657e88f27b3Smrg int i; 658e88f27b3Smrg 659e88f27b3Smrg for (i = 0; i < dev->resources->res->count_connectors; i++) { 660e88f27b3Smrg connector = dev->resources->connectors[i].connector; 661e88f27b3Smrg if (connector && connector->connector_id == id) 662e88f27b3Smrg return connector; 663e88f27b3Smrg } 664e88f27b3Smrg 665e88f27b3Smrg return NULL; 666e88f27b3Smrg} 667e88f27b3Smrg 668e88f27b3Smrgstatic drmModeEncoder *get_encoder_by_id(struct device *dev, uint32_t id) 669e88f27b3Smrg{ 670e88f27b3Smrg drmModeEncoder *encoder; 671e88f27b3Smrg int i; 672e88f27b3Smrg 673e88f27b3Smrg for (i = 0; i < dev->resources->res->count_encoders; i++) { 674e88f27b3Smrg encoder = dev->resources->encoders[i].encoder; 675e88f27b3Smrg if (encoder && encoder->encoder_id == id) 676e88f27b3Smrg return encoder; 677e88f27b3Smrg } 678e88f27b3Smrg 679e88f27b3Smrg return NULL; 680e88f27b3Smrg} 681e88f27b3Smrg 682e88f27b3Smrg/* ----------------------------------------------------------------------------- 683e88f27b3Smrg * Pipes and planes 684e88f27b3Smrg */ 685e88f27b3Smrg 686e88f27b3Smrg/* 687e88f27b3Smrg * Mode setting with the kernel interfaces is a bit of a chore. 688e88f27b3Smrg * First you have to find the connector in question and make sure the 689e88f27b3Smrg * requested mode is available. 690e88f27b3Smrg * Then you need to find the encoder attached to that connector so you 691e88f27b3Smrg * can bind it with a free crtc. 692e88f27b3Smrg */ 693e88f27b3Smrgstruct pipe_arg { 694e88f27b3Smrg uint32_t *con_ids; 695e88f27b3Smrg unsigned int num_cons; 696e88f27b3Smrg uint32_t crtc_id; 697e88f27b3Smrg char mode_str[64]; 698e88f27b3Smrg char format_str[5]; 699e88f27b3Smrg unsigned int vrefresh; 700e88f27b3Smrg unsigned int fourcc; 701e88f27b3Smrg drmModeModeInfo *mode; 702e88f27b3Smrg struct crtc *crtc; 703e88f27b3Smrg unsigned int fb_id[2], current_fb_id; 704e88f27b3Smrg struct timeval start; 705e88f27b3Smrg 706e88f27b3Smrg int swap_count; 707e88f27b3Smrg}; 708e88f27b3Smrg 709e88f27b3Smrgstruct plane_arg { 710e88f27b3Smrg uint32_t crtc_id; /* the id of CRTC to bind to */ 711e88f27b3Smrg bool has_position; 712e88f27b3Smrg int32_t x, y; 713e88f27b3Smrg uint32_t w, h; 714e88f27b3Smrg double scale; 715e88f27b3Smrg unsigned int fb_id; 716e88f27b3Smrg char format_str[5]; /* need to leave room for terminating \0 */ 717e88f27b3Smrg unsigned int fourcc; 718e88f27b3Smrg}; 719e88f27b3Smrg 720e88f27b3Smrgstatic drmModeModeInfo * 721e88f27b3Smrgconnector_find_mode(struct device *dev, uint32_t con_id, const char *mode_str, 722e88f27b3Smrg const unsigned int vrefresh) 723e88f27b3Smrg{ 724e88f27b3Smrg drmModeConnector *connector; 725e88f27b3Smrg drmModeModeInfo *mode; 726e88f27b3Smrg int i; 727e88f27b3Smrg 728e88f27b3Smrg connector = get_connector_by_id(dev, con_id); 729e88f27b3Smrg if (!connector || !connector->count_modes) 730e88f27b3Smrg return NULL; 731e88f27b3Smrg 732e88f27b3Smrg for (i = 0; i < connector->count_modes; i++) { 733e88f27b3Smrg mode = &connector->modes[i]; 734e88f27b3Smrg if (!strcmp(mode->name, mode_str)) { 735e88f27b3Smrg /* If the vertical refresh frequency is not specified then return the 736e88f27b3Smrg * first mode that match with the name. Else, return the mode that match 737e88f27b3Smrg * the name and the specified vertical refresh frequency. 738e88f27b3Smrg */ 739e88f27b3Smrg if (vrefresh == 0) 740e88f27b3Smrg return mode; 741e88f27b3Smrg else if (mode->vrefresh == vrefresh) 742e88f27b3Smrg return mode; 74318210155Smrg } 744e88f27b3Smrg } 74518210155Smrg 746e88f27b3Smrg return NULL; 74718210155Smrg} 74818210155Smrg 749e88f27b3Smrgstatic struct crtc *pipe_find_crtc(struct device *dev, struct pipe_arg *pipe) 75018210155Smrg{ 751e88f27b3Smrg uint32_t possible_crtcs = ~0; 752e88f27b3Smrg uint32_t active_crtcs = 0; 753e88f27b3Smrg unsigned int crtc_idx; 754e88f27b3Smrg unsigned int i; 755e88f27b3Smrg int j; 756e88f27b3Smrg 757e88f27b3Smrg for (i = 0; i < pipe->num_cons; ++i) { 758e88f27b3Smrg uint32_t crtcs_for_connector = 0; 759e88f27b3Smrg drmModeConnector *connector; 760e88f27b3Smrg drmModeEncoder *encoder; 761e88f27b3Smrg int idx; 762e88f27b3Smrg 763e88f27b3Smrg connector = get_connector_by_id(dev, pipe->con_ids[i]); 764e88f27b3Smrg if (!connector) 765e88f27b3Smrg return NULL; 766e88f27b3Smrg 767e88f27b3Smrg for (j = 0; j < connector->count_encoders; ++j) { 768e88f27b3Smrg encoder = get_encoder_by_id(dev, connector->encoders[j]); 769e88f27b3Smrg if (!encoder) 770e88f27b3Smrg continue; 771e88f27b3Smrg 772e88f27b3Smrg crtcs_for_connector |= encoder->possible_crtcs; 773e88f27b3Smrg 774e88f27b3Smrg idx = get_crtc_index(dev, encoder->crtc_id); 775e88f27b3Smrg if (idx >= 0) 776e88f27b3Smrg active_crtcs |= 1 << idx; 777e88f27b3Smrg } 77818210155Smrg 779e88f27b3Smrg possible_crtcs &= crtcs_for_connector; 78018210155Smrg } 78118210155Smrg 782e88f27b3Smrg if (!possible_crtcs) 783e88f27b3Smrg return NULL; 784e88f27b3Smrg 785e88f27b3Smrg /* Return the first possible and active CRTC if one exists, or the first 786e88f27b3Smrg * possible CRTC otherwise. 787e88f27b3Smrg */ 788e88f27b3Smrg if (possible_crtcs & active_crtcs) 789e88f27b3Smrg crtc_idx = ffs(possible_crtcs & active_crtcs); 790e88f27b3Smrg else 791e88f27b3Smrg crtc_idx = ffs(possible_crtcs); 792e88f27b3Smrg 793e88f27b3Smrg return &dev->resources->crtcs[crtc_idx - 1]; 794e88f27b3Smrg} 795e88f27b3Smrg 796e88f27b3Smrgstatic int pipe_find_crtc_and_mode(struct device *dev, struct pipe_arg *pipe) 797e88f27b3Smrg{ 798e88f27b3Smrg drmModeModeInfo *mode = NULL; 799e88f27b3Smrg int i; 800e88f27b3Smrg 801e88f27b3Smrg pipe->mode = NULL; 802e88f27b3Smrg 803e88f27b3Smrg for (i = 0; i < (int)pipe->num_cons; i++) { 804e88f27b3Smrg mode = connector_find_mode(dev, pipe->con_ids[i], 805e88f27b3Smrg pipe->mode_str, pipe->vrefresh); 806e88f27b3Smrg if (mode == NULL) { 807e88f27b3Smrg fprintf(stderr, 808e88f27b3Smrg "failed to find mode \"%s\" for connector %u\n", 809e88f27b3Smrg pipe->mode_str, pipe->con_ids[i]); 810e88f27b3Smrg return -EINVAL; 811e88f27b3Smrg } 81218210155Smrg } 81318210155Smrg 814e88f27b3Smrg /* If the CRTC ID was specified, get the corresponding CRTC. Otherwise 815e88f27b3Smrg * locate a CRTC that can be attached to all the connectors. 816e88f27b3Smrg */ 817e88f27b3Smrg if (pipe->crtc_id != (uint32_t)-1) { 818e88f27b3Smrg for (i = 0; i < dev->resources->res->count_crtcs; i++) { 819e88f27b3Smrg struct crtc *crtc = &dev->resources->crtcs[i]; 820e88f27b3Smrg 821e88f27b3Smrg if (pipe->crtc_id == crtc->crtc->crtc_id) { 822e88f27b3Smrg pipe->crtc = crtc; 823e88f27b3Smrg break; 824e88f27b3Smrg } 825d049871aSmrg } 826e88f27b3Smrg } else { 827e88f27b3Smrg pipe->crtc = pipe_find_crtc(dev, pipe); 82818210155Smrg } 829d049871aSmrg 830e88f27b3Smrg if (!pipe->crtc) { 831e88f27b3Smrg fprintf(stderr, "failed to find CRTC for pipe\n"); 832e88f27b3Smrg return -EINVAL; 833e88f27b3Smrg } 834d049871aSmrg 835e88f27b3Smrg pipe->mode = mode; 836e88f27b3Smrg pipe->crtc->mode = mode; 83718210155Smrg 83818210155Smrg return 0; 83918210155Smrg} 84018210155Smrg 841e88f27b3Smrg/* ----------------------------------------------------------------------------- 842e88f27b3Smrg * Properties 843e88f27b3Smrg */ 844e88f27b3Smrg 845e88f27b3Smrgstruct property_arg { 846e88f27b3Smrg uint32_t obj_id; 847e88f27b3Smrg uint32_t obj_type; 848e88f27b3Smrg char name[DRM_PROP_NAME_LEN+1]; 849e88f27b3Smrg uint32_t prop_id; 850e88f27b3Smrg uint64_t value; 851e88f27b3Smrg}; 852e88f27b3Smrg 853e88f27b3Smrgstatic void set_property(struct device *dev, struct property_arg *p) 85422944501Smrg{ 855e88f27b3Smrg drmModeObjectProperties *props = NULL; 856e88f27b3Smrg drmModePropertyRes **props_info = NULL; 857e88f27b3Smrg const char *obj_type; 858e88f27b3Smrg int ret; 859e88f27b3Smrg int i; 86022944501Smrg 861e88f27b3Smrg p->obj_type = 0; 862e88f27b3Smrg p->prop_id = 0; 863e88f27b3Smrg 864e88f27b3Smrg#define find_object(_res, __res, type, Type) \ 865e88f27b3Smrg do { \ 866e88f27b3Smrg for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \ 867e88f27b3Smrg struct type *obj = &(_res)->type##s[i]; \ 868e88f27b3Smrg if (obj->type->type##_id != p->obj_id) \ 869e88f27b3Smrg continue; \ 870e88f27b3Smrg p->obj_type = DRM_MODE_OBJECT_##Type; \ 871e88f27b3Smrg obj_type = #Type; \ 872e88f27b3Smrg props = obj->props; \ 873e88f27b3Smrg props_info = obj->props_info; \ 874e88f27b3Smrg } \ 875e88f27b3Smrg } while(0) \ 876e88f27b3Smrg 877e88f27b3Smrg find_object(dev->resources, res, crtc, CRTC); 878e88f27b3Smrg if (p->obj_type == 0) 879e88f27b3Smrg find_object(dev->resources, res, connector, CONNECTOR); 880e88f27b3Smrg if (p->obj_type == 0) 881e88f27b3Smrg find_object(dev->resources, plane_res, plane, PLANE); 882e88f27b3Smrg if (p->obj_type == 0) { 883e88f27b3Smrg fprintf(stderr, "Object %i not found, can't set property\n", 884e88f27b3Smrg p->obj_id); 885e88f27b3Smrg return; 886e88f27b3Smrg } 88722944501Smrg 888e88f27b3Smrg if (!props) { 889e88f27b3Smrg fprintf(stderr, "%s %i has no properties\n", 890e88f27b3Smrg obj_type, p->obj_id); 891e88f27b3Smrg return; 89222944501Smrg } 89322944501Smrg 894e88f27b3Smrg for (i = 0; i < (int)props->count_props; ++i) { 895e88f27b3Smrg if (!props_info[i]) 896e88f27b3Smrg continue; 897e88f27b3Smrg if (strcmp(props_info[i]->name, p->name) == 0) 898e88f27b3Smrg break; 89922944501Smrg } 90022944501Smrg 901e88f27b3Smrg if (i == (int)props->count_props) { 902e88f27b3Smrg fprintf(stderr, "%s %i has no %s property\n", 903e88f27b3Smrg obj_type, p->obj_id, p->name); 904e88f27b3Smrg return; 905e88f27b3Smrg } 90622944501Smrg 907e88f27b3Smrg p->prop_id = props->props[i]; 90822944501Smrg 909e88f27b3Smrg ret = drmModeObjectSetProperty(dev->fd, p->obj_id, p->obj_type, 910e88f27b3Smrg p->prop_id, p->value); 911e88f27b3Smrg if (ret < 0) 912e88f27b3Smrg fprintf(stderr, "failed to set %s %i property %s to %" PRIu64 ": %s\n", 913e88f27b3Smrg obj_type, p->obj_id, p->name, p->value, strerror(errno)); 91422944501Smrg} 91522944501Smrg 916e88f27b3Smrg/* -------------------------------------------------------------------------- */ 917e88f27b3Smrg 918e88f27b3Smrgstatic void 91922944501Smrgpage_flip_handler(int fd, unsigned int frame, 92022944501Smrg unsigned int sec, unsigned int usec, void *data) 92122944501Smrg{ 922e88f27b3Smrg struct pipe_arg *pipe; 92322944501Smrg unsigned int new_fb_id; 92422944501Smrg struct timeval end; 92522944501Smrg double t; 92622944501Smrg 927e88f27b3Smrg pipe = data; 928e88f27b3Smrg if (pipe->current_fb_id == pipe->fb_id[0]) 929e88f27b3Smrg new_fb_id = pipe->fb_id[1]; 93022944501Smrg else 931e88f27b3Smrg new_fb_id = pipe->fb_id[0]; 932e88f27b3Smrg 933e88f27b3Smrg drmModePageFlip(fd, pipe->crtc->crtc->crtc_id, new_fb_id, 934e88f27b3Smrg DRM_MODE_PAGE_FLIP_EVENT, pipe); 935e88f27b3Smrg pipe->current_fb_id = new_fb_id; 936e88f27b3Smrg pipe->swap_count++; 937e88f27b3Smrg if (pipe->swap_count == 60) { 93822944501Smrg gettimeofday(&end, NULL); 93922944501Smrg t = end.tv_sec + end.tv_usec * 1e-6 - 940e88f27b3Smrg (pipe->start.tv_sec + pipe->start.tv_usec * 1e-6); 941e88f27b3Smrg fprintf(stderr, "freq: %.02fHz\n", pipe->swap_count / t); 942e88f27b3Smrg pipe->swap_count = 0; 943e88f27b3Smrg pipe->start = end; 94422944501Smrg } 94522944501Smrg} 94622944501Smrg 947e88f27b3Smrgstatic int set_plane(struct device *dev, struct plane_arg *p) 94818210155Smrg{ 949e88f27b3Smrg drmModePlane *ovr; 950e88f27b3Smrg uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */ 951e88f27b3Smrg uint32_t plane_id = 0; 952e88f27b3Smrg struct kms_bo *plane_bo; 953e88f27b3Smrg uint32_t plane_flags = 0; 954e88f27b3Smrg int crtc_x, crtc_y, crtc_w, crtc_h; 955e88f27b3Smrg struct crtc *crtc = NULL; 956e88f27b3Smrg unsigned int pipe; 957e88f27b3Smrg unsigned int i; 958e88f27b3Smrg 959e88f27b3Smrg /* Find an unused plane which can be connected to our CRTC. Find the 960e88f27b3Smrg * CRTC index first, then iterate over available planes. 961e88f27b3Smrg */ 962e88f27b3Smrg for (i = 0; i < (unsigned int)dev->resources->res->count_crtcs; i++) { 963e88f27b3Smrg if (p->crtc_id == dev->resources->res->crtcs[i]) { 964e88f27b3Smrg crtc = &dev->resources->crtcs[i]; 965e88f27b3Smrg pipe = i; 966e88f27b3Smrg break; 967e88f27b3Smrg } 968e88f27b3Smrg } 96918210155Smrg 970e88f27b3Smrg if (!crtc) { 971e88f27b3Smrg fprintf(stderr, "CRTC %u not found\n", p->crtc_id); 972e88f27b3Smrg return -1; 973e88f27b3Smrg } 974e88f27b3Smrg 975e88f27b3Smrg for (i = 0; i < dev->resources->plane_res->count_planes && !plane_id; i++) { 976e88f27b3Smrg ovr = dev->resources->planes[i].plane; 977e88f27b3Smrg if (!ovr) 97818210155Smrg continue; 979e88f27b3Smrg 980e88f27b3Smrg if ((ovr->possible_crtcs & (1 << pipe)) && !ovr->crtc_id) 981e88f27b3Smrg plane_id = ovr->plane_id; 98218210155Smrg } 98318210155Smrg 984e88f27b3Smrg if (!plane_id) { 985e88f27b3Smrg fprintf(stderr, "no unused plane available for CRTC %u\n", 986e88f27b3Smrg crtc->crtc->crtc_id); 987e88f27b3Smrg return -1; 988e88f27b3Smrg } 989e88f27b3Smrg 990e88f27b3Smrg fprintf(stderr, "testing %dx%d@%s overlay plane %u\n", 991e88f27b3Smrg p->w, p->h, p->format_str, plane_id); 992e88f27b3Smrg 993e88f27b3Smrg plane_bo = create_test_buffer(dev->kms, p->fourcc, p->w, p->h, handles, 994e88f27b3Smrg pitches, offsets, PATTERN_TILES); 995e88f27b3Smrg if (plane_bo == NULL) 996e88f27b3Smrg return -1; 997e88f27b3Smrg 998e88f27b3Smrg /* just use single plane format for now.. */ 999e88f27b3Smrg if (drmModeAddFB2(dev->fd, p->w, p->h, p->fourcc, 1000e88f27b3Smrg handles, pitches, offsets, &p->fb_id, plane_flags)) { 1001e88f27b3Smrg fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); 1002e88f27b3Smrg return -1; 1003e88f27b3Smrg } 1004e88f27b3Smrg 1005e88f27b3Smrg crtc_w = p->w * p->scale; 1006e88f27b3Smrg crtc_h = p->h * p->scale; 1007e88f27b3Smrg if (!p->has_position) { 1008e88f27b3Smrg /* Default to the middle of the screen */ 1009e88f27b3Smrg crtc_x = (crtc->mode->hdisplay - crtc_w) / 2; 1010e88f27b3Smrg crtc_y = (crtc->mode->vdisplay - crtc_h) / 2; 1011e88f27b3Smrg } else { 1012e88f27b3Smrg crtc_x = p->x; 1013e88f27b3Smrg crtc_y = p->y; 101418210155Smrg } 101518210155Smrg 1016e88f27b3Smrg /* note src coords (last 4 args) are in Q16 format */ 1017e88f27b3Smrg if (drmModeSetPlane(dev->fd, plane_id, crtc->crtc->crtc_id, p->fb_id, 1018e88f27b3Smrg plane_flags, crtc_x, crtc_y, crtc_w, crtc_h, 1019e88f27b3Smrg 0, 0, p->w << 16, p->h << 16)) { 1020e88f27b3Smrg fprintf(stderr, "failed to enable plane: %s\n", 1021e88f27b3Smrg strerror(errno)); 1022e88f27b3Smrg return -1; 1023e88f27b3Smrg } 1024e88f27b3Smrg 1025e88f27b3Smrg ovr->crtc_id = crtc->crtc->crtc_id; 1026e88f27b3Smrg 1027e88f27b3Smrg return 0; 1028e88f27b3Smrg} 1029e88f27b3Smrg 1030e88f27b3Smrgstatic void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count) 1031e88f27b3Smrg{ 1032e88f27b3Smrg uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */ 1033e88f27b3Smrg unsigned int fb_id; 1034e88f27b3Smrg struct kms_bo *bo; 1035e88f27b3Smrg unsigned int i; 1036e88f27b3Smrg unsigned int j; 1037e88f27b3Smrg int ret, x; 1038e88f27b3Smrg 1039e88f27b3Smrg dev->mode.width = 0; 1040e88f27b3Smrg dev->mode.height = 0; 1041e88f27b3Smrg 1042e88f27b3Smrg for (i = 0; i < count; i++) { 1043e88f27b3Smrg struct pipe_arg *pipe = &pipes[i]; 1044e88f27b3Smrg 1045e88f27b3Smrg ret = pipe_find_crtc_and_mode(dev, pipe); 1046e88f27b3Smrg if (ret < 0) 1047e88f27b3Smrg continue; 1048e88f27b3Smrg 1049e88f27b3Smrg dev->mode.width += pipe->mode->hdisplay; 1050e88f27b3Smrg if (dev->mode.height < pipe->mode->vdisplay) 1051e88f27b3Smrg dev->mode.height = pipe->mode->vdisplay; 1052e88f27b3Smrg } 1053e88f27b3Smrg 1054e88f27b3Smrg bo = create_test_buffer(dev->kms, pipes[0].fourcc, 1055e88f27b3Smrg dev->mode.width, dev->mode.height, 1056e88f27b3Smrg handles, pitches, offsets, PATTERN_SMPTE); 1057e88f27b3Smrg if (bo == NULL) 105818210155Smrg return; 105918210155Smrg 1060e88f27b3Smrg ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height, 1061e88f27b3Smrg pipes[0].fourcc, handles, pitches, offsets, &fb_id, 0); 106218210155Smrg if (ret) { 1063e88f27b3Smrg fprintf(stderr, "failed to add fb (%ux%u): %s\n", 1064e88f27b3Smrg dev->mode.width, dev->mode.height, strerror(errno)); 106518210155Smrg return; 106618210155Smrg } 106718210155Smrg 106818210155Smrg x = 0; 106918210155Smrg for (i = 0; i < count; i++) { 1070e88f27b3Smrg struct pipe_arg *pipe = &pipes[i]; 1071e88f27b3Smrg 1072e88f27b3Smrg if (pipe->mode == NULL) 107318210155Smrg continue; 107418210155Smrg 1075e88f27b3Smrg printf("setting mode %s-%dHz@%s on connectors ", 1076e88f27b3Smrg pipe->mode_str, pipe->mode->vrefresh, pipe->format_str); 1077e88f27b3Smrg for (j = 0; j < pipe->num_cons; ++j) 1078e88f27b3Smrg printf("%u, ", pipe->con_ids[j]); 1079e88f27b3Smrg printf("crtc %d\n", pipe->crtc->crtc->crtc_id); 1080e88f27b3Smrg 1081e88f27b3Smrg ret = drmModeSetCrtc(dev->fd, pipe->crtc->crtc->crtc_id, fb_id, 1082e88f27b3Smrg x, 0, pipe->con_ids, pipe->num_cons, 1083e88f27b3Smrg pipe->mode); 1084e88f27b3Smrg 1085e88f27b3Smrg /* XXX: Actually check if this is needed */ 1086e88f27b3Smrg drmModeDirtyFB(dev->fd, fb_id, NULL, 0); 108718210155Smrg 1088e88f27b3Smrg x += pipe->mode->hdisplay; 108918210155Smrg 109018210155Smrg if (ret) { 109118210155Smrg fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); 109218210155Smrg return; 109318210155Smrg } 109418210155Smrg } 109522944501Smrg 1096e88f27b3Smrg dev->mode.bo = bo; 1097e88f27b3Smrg dev->mode.fb_id = fb_id; 1098e88f27b3Smrg} 109922944501Smrg 1100e88f27b3Smrgstatic void set_planes(struct device *dev, struct plane_arg *p, unsigned int count) 1101e88f27b3Smrg{ 1102e88f27b3Smrg unsigned int i; 1103e88f27b3Smrg 1104e88f27b3Smrg /* set up planes/overlays */ 1105e88f27b3Smrg for (i = 0; i < count; i++) 1106e88f27b3Smrg if (set_plane(dev, &p[i])) 1107e88f27b3Smrg return; 1108e88f27b3Smrg} 1109e88f27b3Smrg 1110a7d7de1eSmrgstatic void set_cursors(struct device *dev, struct pipe_arg *pipes, unsigned int count) 1111a7d7de1eSmrg{ 1112a7d7de1eSmrg uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */ 1113a7d7de1eSmrg struct kms_bo *bo; 1114a7d7de1eSmrg unsigned int i; 1115a7d7de1eSmrg int ret; 1116a7d7de1eSmrg 1117a7d7de1eSmrg /* maybe make cursor width/height configurable some day */ 1118a7d7de1eSmrg uint32_t cw = 64; 1119a7d7de1eSmrg uint32_t ch = 64; 1120a7d7de1eSmrg 1121a7d7de1eSmrg /* create cursor bo.. just using PATTERN_PLAIN as it has 1122a7d7de1eSmrg * translucent alpha 1123a7d7de1eSmrg */ 1124a7d7de1eSmrg bo = create_test_buffer(dev->kms, DRM_FORMAT_ARGB8888, 1125a7d7de1eSmrg cw, ch, handles, pitches, offsets, PATTERN_PLAIN); 1126a7d7de1eSmrg if (bo == NULL) 1127a7d7de1eSmrg return; 1128a7d7de1eSmrg 1129a7d7de1eSmrg for (i = 0; i < count; i++) { 1130a7d7de1eSmrg struct pipe_arg *pipe = &pipes[i]; 1131a7d7de1eSmrg ret = cursor_init(dev->fd, handles[0], 1132a7d7de1eSmrg pipe->crtc->crtc->crtc_id, 1133a7d7de1eSmrg pipe->mode->hdisplay, pipe->mode->vdisplay, 1134a7d7de1eSmrg cw, ch); 1135a7d7de1eSmrg if (ret) { 1136a7d7de1eSmrg fprintf(stderr, "failed to init cursor for CRTC[%u]\n", 1137a7d7de1eSmrg pipe->crtc_id); 1138a7d7de1eSmrg return; 1139a7d7de1eSmrg } 1140a7d7de1eSmrg } 1141a7d7de1eSmrg 1142a7d7de1eSmrg cursor_start(); 1143a7d7de1eSmrg} 1144a7d7de1eSmrg 1145a7d7de1eSmrgstatic void clear_cursors(struct device *dev) 1146a7d7de1eSmrg{ 1147a7d7de1eSmrg cursor_stop(); 1148a7d7de1eSmrg} 1149a7d7de1eSmrg 1150e88f27b3Smrgstatic void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned int count) 1151e88f27b3Smrg{ 1152e88f27b3Smrg uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */ 1153e88f27b3Smrg unsigned int other_fb_id; 1154e88f27b3Smrg struct kms_bo *other_bo; 1155e88f27b3Smrg drmEventContext evctx; 1156e88f27b3Smrg unsigned int i; 1157e88f27b3Smrg int ret; 1158e88f27b3Smrg 1159e88f27b3Smrg other_bo = create_test_buffer(dev->kms, pipes[0].fourcc, 1160e88f27b3Smrg dev->mode.width, dev->mode.height, 1161e88f27b3Smrg handles, pitches, offsets, PATTERN_PLAIN); 1162e88f27b3Smrg if (other_bo == NULL) 116322944501Smrg return; 116422944501Smrg 1165e88f27b3Smrg ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height, 1166e88f27b3Smrg pipes[0].fourcc, handles, pitches, offsets, 1167e88f27b3Smrg &other_fb_id, 0); 116822944501Smrg if (ret) { 116922944501Smrg fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); 117022944501Smrg return; 117122944501Smrg } 117222944501Smrg 117322944501Smrg for (i = 0; i < count; i++) { 1174e88f27b3Smrg struct pipe_arg *pipe = &pipes[i]; 1175e88f27b3Smrg 1176e88f27b3Smrg if (pipe->mode == NULL) 117722944501Smrg continue; 117822944501Smrg 1179e88f27b3Smrg ret = drmModePageFlip(dev->fd, pipe->crtc->crtc->crtc_id, 1180e88f27b3Smrg other_fb_id, DRM_MODE_PAGE_FLIP_EVENT, 1181e88f27b3Smrg pipe); 1182e88f27b3Smrg if (ret) { 1183e88f27b3Smrg fprintf(stderr, "failed to page flip: %s\n", strerror(errno)); 1184e88f27b3Smrg return; 1185e88f27b3Smrg } 1186e88f27b3Smrg gettimeofday(&pipe->start, NULL); 1187e88f27b3Smrg pipe->swap_count = 0; 1188e88f27b3Smrg pipe->fb_id[0] = dev->mode.fb_id; 1189e88f27b3Smrg pipe->fb_id[1] = other_fb_id; 1190e88f27b3Smrg pipe->current_fb_id = other_fb_id; 119122944501Smrg } 119222944501Smrg 119322944501Smrg memset(&evctx, 0, sizeof evctx); 119422944501Smrg evctx.version = DRM_EVENT_CONTEXT_VERSION; 119522944501Smrg evctx.vblank_handler = NULL; 119622944501Smrg evctx.page_flip_handler = page_flip_handler; 119722944501Smrg 119822944501Smrg while (1) { 119922944501Smrg#if 0 120022944501Smrg struct pollfd pfd[2]; 120122944501Smrg 120222944501Smrg pfd[0].fd = 0; 120322944501Smrg pfd[0].events = POLLIN; 120422944501Smrg pfd[1].fd = fd; 120522944501Smrg pfd[1].events = POLLIN; 120622944501Smrg 120722944501Smrg if (poll(pfd, 2, -1) < 0) { 120822944501Smrg fprintf(stderr, "poll error\n"); 120922944501Smrg break; 121022944501Smrg } 121122944501Smrg 121222944501Smrg if (pfd[0].revents) 121322944501Smrg break; 121422944501Smrg#else 121522944501Smrg struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; 121622944501Smrg fd_set fds; 121722944501Smrg int ret; 121822944501Smrg 121922944501Smrg FD_ZERO(&fds); 122022944501Smrg FD_SET(0, &fds); 1221e88f27b3Smrg FD_SET(dev->fd, &fds); 1222e88f27b3Smrg ret = select(dev->fd + 1, &fds, NULL, NULL, &timeout); 122322944501Smrg 122422944501Smrg if (ret <= 0) { 122522944501Smrg fprintf(stderr, "select timed out or error (ret %d)\n", 122622944501Smrg ret); 122722944501Smrg continue; 122822944501Smrg } else if (FD_ISSET(0, &fds)) { 122922944501Smrg break; 123022944501Smrg } 123122944501Smrg#endif 123222944501Smrg 1233e88f27b3Smrg drmHandleEvent(dev->fd, &evctx); 123422944501Smrg } 1235e88f27b3Smrg 1236e88f27b3Smrg kms_bo_destroy(&other_bo); 123718210155Smrg} 123818210155Smrg 1239e88f27b3Smrg#define min(a, b) ((a) < (b) ? (a) : (b)) 124018210155Smrg 1241e88f27b3Smrgstatic int parse_connector(struct pipe_arg *pipe, const char *arg) 124218210155Smrg{ 1243e88f27b3Smrg unsigned int len; 1244e88f27b3Smrg unsigned int i; 1245e88f27b3Smrg const char *p; 1246e88f27b3Smrg char *endp; 1247e88f27b3Smrg 1248e88f27b3Smrg pipe->vrefresh = 0; 1249e88f27b3Smrg pipe->crtc_id = (uint32_t)-1; 1250e88f27b3Smrg strcpy(pipe->format_str, "XR24"); 1251e88f27b3Smrg 1252e88f27b3Smrg /* Count the number of connectors and allocate them. */ 1253e88f27b3Smrg pipe->num_cons = 1; 1254e88f27b3Smrg for (p = arg; isdigit(*p) || *p == ','; ++p) { 1255e88f27b3Smrg if (*p == ',') 1256e88f27b3Smrg pipe->num_cons++; 1257e88f27b3Smrg } 1258e88f27b3Smrg 1259e88f27b3Smrg pipe->con_ids = malloc(pipe->num_cons * sizeof *pipe->con_ids); 1260e88f27b3Smrg if (pipe->con_ids == NULL) 1261e88f27b3Smrg return -1; 1262e88f27b3Smrg 1263e88f27b3Smrg /* Parse the connectors. */ 1264e88f27b3Smrg for (i = 0, p = arg; i < pipe->num_cons; ++i, p = endp + 1) { 1265e88f27b3Smrg pipe->con_ids[i] = strtoul(p, &endp, 10); 1266e88f27b3Smrg if (*endp != ',') 1267e88f27b3Smrg break; 1268e88f27b3Smrg } 1269e88f27b3Smrg 1270e88f27b3Smrg if (i != pipe->num_cons - 1) 1271e88f27b3Smrg return -1; 1272e88f27b3Smrg 1273e88f27b3Smrg /* Parse the remaining parameters. */ 1274e88f27b3Smrg if (*endp == '@') { 1275e88f27b3Smrg arg = endp + 1; 1276e88f27b3Smrg pipe->crtc_id = strtoul(arg, &endp, 10); 1277e88f27b3Smrg } 1278e88f27b3Smrg if (*endp != ':') 1279e88f27b3Smrg return -1; 1280e88f27b3Smrg 1281e88f27b3Smrg arg = endp + 1; 1282e88f27b3Smrg 1283e88f27b3Smrg /* Search for the vertical refresh or the format. */ 1284e88f27b3Smrg p = strpbrk(arg, "-@"); 1285e88f27b3Smrg if (p == NULL) 1286e88f27b3Smrg p = arg + strlen(arg); 1287e88f27b3Smrg len = min(sizeof pipe->mode_str - 1, (unsigned int)(p - arg)); 1288e88f27b3Smrg strncpy(pipe->mode_str, arg, len); 1289e88f27b3Smrg pipe->mode_str[len] = '\0'; 1290e88f27b3Smrg 1291e88f27b3Smrg if (*p == '-') { 1292e88f27b3Smrg pipe->vrefresh = strtoul(p + 1, &endp, 10); 1293e88f27b3Smrg p = endp; 1294e88f27b3Smrg } 1295e88f27b3Smrg 1296e88f27b3Smrg if (*p == '@') { 1297e88f27b3Smrg strncpy(pipe->format_str, p + 1, 4); 1298e88f27b3Smrg pipe->format_str[4] = '\0'; 1299e88f27b3Smrg } 1300e88f27b3Smrg 1301e88f27b3Smrg pipe->fourcc = format_fourcc(pipe->format_str); 1302e88f27b3Smrg if (pipe->fourcc == 0) { 1303e88f27b3Smrg fprintf(stderr, "unknown format %s\n", pipe->format_str); 1304e88f27b3Smrg return -1; 1305e88f27b3Smrg } 1306e88f27b3Smrg 1307e88f27b3Smrg return 0; 1308e88f27b3Smrg} 1309e88f27b3Smrg 1310e88f27b3Smrgstatic int parse_plane(struct plane_arg *plane, const char *p) 1311e88f27b3Smrg{ 1312e88f27b3Smrg char *end; 1313e88f27b3Smrg 1314e88f27b3Smrg memset(plane, 0, sizeof *plane); 1315e88f27b3Smrg 1316e88f27b3Smrg plane->crtc_id = strtoul(p, &end, 10); 1317e88f27b3Smrg if (*end != ':') 1318e88f27b3Smrg return -EINVAL; 1319e88f27b3Smrg 1320e88f27b3Smrg p = end + 1; 1321e88f27b3Smrg plane->w = strtoul(p, &end, 10); 1322e88f27b3Smrg if (*end != 'x') 1323e88f27b3Smrg return -EINVAL; 1324e88f27b3Smrg 1325e88f27b3Smrg p = end + 1; 1326e88f27b3Smrg plane->h = strtoul(p, &end, 10); 1327e88f27b3Smrg 1328e88f27b3Smrg if (*end == '+' || *end == '-') { 1329e88f27b3Smrg plane->x = strtol(end, &end, 10); 1330e88f27b3Smrg if (*end != '+' && *end != '-') 1331e88f27b3Smrg return -EINVAL; 1332e88f27b3Smrg plane->y = strtol(end, &end, 10); 1333e88f27b3Smrg 1334e88f27b3Smrg plane->has_position = true; 1335e88f27b3Smrg } 1336e88f27b3Smrg 1337e88f27b3Smrg if (*end == '*') { 1338e88f27b3Smrg p = end + 1; 1339e88f27b3Smrg plane->scale = strtod(p, &end); 1340e88f27b3Smrg if (plane->scale <= 0.0) 1341e88f27b3Smrg return -EINVAL; 1342e88f27b3Smrg } else { 1343e88f27b3Smrg plane->scale = 1.0; 1344e88f27b3Smrg } 1345e88f27b3Smrg 1346e88f27b3Smrg if (*end == '@') { 1347e88f27b3Smrg p = end + 1; 1348e88f27b3Smrg if (strlen(p) != 4) 1349e88f27b3Smrg return -EINVAL; 1350e88f27b3Smrg 1351e88f27b3Smrg strcpy(plane->format_str, p); 1352e88f27b3Smrg } else { 1353e88f27b3Smrg strcpy(plane->format_str, "XR24"); 1354e88f27b3Smrg } 1355e88f27b3Smrg 1356e88f27b3Smrg plane->fourcc = format_fourcc(plane->format_str); 1357e88f27b3Smrg if (plane->fourcc == 0) { 1358e88f27b3Smrg fprintf(stderr, "unknown format %s\n", plane->format_str); 1359e88f27b3Smrg return -EINVAL; 1360e88f27b3Smrg } 1361e88f27b3Smrg 1362e88f27b3Smrg return 0; 1363e88f27b3Smrg} 1364e88f27b3Smrg 1365e88f27b3Smrgstatic int parse_property(struct property_arg *p, const char *arg) 1366e88f27b3Smrg{ 1367e88f27b3Smrg if (sscanf(arg, "%d:%32[^:]:%" SCNu64, &p->obj_id, p->name, &p->value) != 3) 1368e88f27b3Smrg return -1; 1369e88f27b3Smrg 1370e88f27b3Smrg p->obj_type = 0; 1371e88f27b3Smrg p->name[DRM_PROP_NAME_LEN] = '\0'; 1372e88f27b3Smrg 1373e88f27b3Smrg return 0; 1374e88f27b3Smrg} 1375e88f27b3Smrg 1376e88f27b3Smrgstatic void usage(char *name) 1377e88f27b3Smrg{ 1378a7d7de1eSmrg fprintf(stderr, "usage: %s [-cDdefMPpsCvw]\n", name); 1379e88f27b3Smrg 1380e88f27b3Smrg fprintf(stderr, "\n Query options:\n\n"); 138118210155Smrg fprintf(stderr, "\t-c\tlist connectors\n"); 1382e88f27b3Smrg fprintf(stderr, "\t-e\tlist encoders\n"); 138318210155Smrg fprintf(stderr, "\t-f\tlist framebuffers\n"); 1384e88f27b3Smrg fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n"); 1385e88f27b3Smrg 1386e88f27b3Smrg fprintf(stderr, "\n Test options:\n\n"); 1387e88f27b3Smrg fprintf(stderr, "\t-P <crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]\tset a plane\n"); 1388e88f27b3Smrg fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:<mode>[-<vrefresh>][@<format>]\tset a mode\n"); 1389a7d7de1eSmrg fprintf(stderr, "\t-C\ttest hw cursor\n"); 139022944501Smrg fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); 1391e88f27b3Smrg fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n"); 1392e88f27b3Smrg 1393e88f27b3Smrg fprintf(stderr, "\n Generic options:\n\n"); 1394e88f27b3Smrg fprintf(stderr, "\t-d\tdrop master after mode set\n"); 1395e88f27b3Smrg fprintf(stderr, "\t-M module\tuse the given driver\n"); 1396e88f27b3Smrg fprintf(stderr, "\t-D device\tuse the given device\n"); 1397e88f27b3Smrg 139818210155Smrg fprintf(stderr, "\n\tDefault is to dump all info.\n"); 139918210155Smrg exit(0); 140018210155Smrg} 140118210155Smrg 1402e88f27b3Smrgstatic int page_flipping_supported(void) 140322944501Smrg{ 1404e88f27b3Smrg /*FIXME: generic ioctl needed? */ 1405e88f27b3Smrg return 1; 1406e88f27b3Smrg#if 0 140722944501Smrg int ret, value; 140822944501Smrg struct drm_i915_getparam gp; 140922944501Smrg 141022944501Smrg gp.param = I915_PARAM_HAS_PAGEFLIPPING; 141122944501Smrg gp.value = &value; 141222944501Smrg 141322944501Smrg ret = drmCommandWriteRead(fd, DRM_I915_GETPARAM, &gp, sizeof(gp)); 141422944501Smrg if (ret) { 141522944501Smrg fprintf(stderr, "drm_i915_getparam: %m\n"); 141622944501Smrg return 0; 141722944501Smrg } 141822944501Smrg 141922944501Smrg return *gp.value; 1420e88f27b3Smrg#endif 142122944501Smrg} 142222944501Smrg 1423a7d7de1eSmrgstatic int cursor_supported(void) 1424a7d7de1eSmrg{ 1425a7d7de1eSmrg /*FIXME: generic ioctl needed? */ 1426a7d7de1eSmrg return 1; 1427a7d7de1eSmrg} 1428a7d7de1eSmrg 1429a7d7de1eSmrgstatic char optstr[] = "cdD:efM:P:ps:Cvw:"; 1430e88f27b3Smrg 143118210155Smrgint main(int argc, char **argv) 143218210155Smrg{ 1433e88f27b3Smrg struct device dev; 1434e88f27b3Smrg 143518210155Smrg int c; 1436e88f27b3Smrg int encoders = 0, connectors = 0, crtcs = 0, planes = 0, framebuffers = 0; 1437e88f27b3Smrg int drop_master = 0; 143822944501Smrg int test_vsync = 0; 1439a7d7de1eSmrg int test_cursor = 0; 1440a884aba1Smrg const char *modules[] = { "i915", "radeon", "nouveau", "vmwgfx", "omapdrm", "exynos", "tilcdc", "msm", "sti" }; 1441e88f27b3Smrg char *device = NULL; 1442e88f27b3Smrg char *module = NULL; 1443e88f27b3Smrg unsigned int i; 1444e88f27b3Smrg int count = 0, plane_count = 0; 1445e88f27b3Smrg unsigned int prop_count = 0; 1446e88f27b3Smrg struct pipe_arg *pipe_args = NULL; 1447e88f27b3Smrg struct plane_arg *plane_args = NULL; 1448e88f27b3Smrg struct property_arg *prop_args = NULL; 1449e88f27b3Smrg unsigned int args = 0; 1450e88f27b3Smrg int ret; 1451e88f27b3Smrg 1452e88f27b3Smrg memset(&dev, 0, sizeof dev); 1453e88f27b3Smrg 145418210155Smrg opterr = 0; 145518210155Smrg while ((c = getopt(argc, argv, optstr)) != -1) { 1456e88f27b3Smrg args++; 1457e88f27b3Smrg 145818210155Smrg switch (c) { 145918210155Smrg case 'c': 146018210155Smrg connectors = 1; 146118210155Smrg break; 1462e88f27b3Smrg case 'D': 1463e88f27b3Smrg device = optarg; 1464e88f27b3Smrg args--; 1465e88f27b3Smrg break; 1466e88f27b3Smrg case 'd': 1467e88f27b3Smrg drop_master = 1; 146818210155Smrg break; 1469e88f27b3Smrg case 'e': 1470e88f27b3Smrg encoders = 1; 147118210155Smrg break; 147218210155Smrg case 'f': 147318210155Smrg framebuffers = 1; 147418210155Smrg break; 1475e88f27b3Smrg case 'M': 1476e88f27b3Smrg module = optarg; 1477e88f27b3Smrg /* Preserve the default behaviour of dumping all information. */ 1478e88f27b3Smrg args--; 1479e88f27b3Smrg break; 1480e88f27b3Smrg case 'P': 1481e88f27b3Smrg plane_args = realloc(plane_args, 1482e88f27b3Smrg (plane_count + 1) * sizeof *plane_args); 1483e88f27b3Smrg if (plane_args == NULL) { 1484e88f27b3Smrg fprintf(stderr, "memory allocation failed\n"); 1485e88f27b3Smrg return 1; 1486e88f27b3Smrg } 1487e88f27b3Smrg 1488e88f27b3Smrg if (parse_plane(&plane_args[plane_count], optarg) < 0) 1489e88f27b3Smrg usage(argv[0]); 1490e88f27b3Smrg 1491e88f27b3Smrg plane_count++; 1492e88f27b3Smrg break; 1493e88f27b3Smrg case 'p': 1494e88f27b3Smrg crtcs = 1; 1495e88f27b3Smrg planes = 1; 149622944501Smrg break; 149718210155Smrg case 's': 1498e88f27b3Smrg pipe_args = realloc(pipe_args, 1499e88f27b3Smrg (count + 1) * sizeof *pipe_args); 1500e88f27b3Smrg if (pipe_args == NULL) { 1501e88f27b3Smrg fprintf(stderr, "memory allocation failed\n"); 1502e88f27b3Smrg return 1; 1503e88f27b3Smrg } 1504e88f27b3Smrg 1505e88f27b3Smrg if (parse_connector(&pipe_args[count], optarg) < 0) 150618210155Smrg usage(argv[0]); 1507e88f27b3Smrg 150818210155Smrg count++; 150918210155Smrg break; 1510a7d7de1eSmrg case 'C': 1511a7d7de1eSmrg test_cursor = 1; 1512a7d7de1eSmrg break; 1513e88f27b3Smrg case 'v': 1514e88f27b3Smrg test_vsync = 1; 1515e88f27b3Smrg break; 1516e88f27b3Smrg case 'w': 1517e88f27b3Smrg prop_args = realloc(prop_args, 1518e88f27b3Smrg (prop_count + 1) * sizeof *prop_args); 1519e88f27b3Smrg if (prop_args == NULL) { 1520e88f27b3Smrg fprintf(stderr, "memory allocation failed\n"); 1521e88f27b3Smrg return 1; 1522e88f27b3Smrg } 1523e88f27b3Smrg 1524e88f27b3Smrg if (parse_property(&prop_args[prop_count], optarg) < 0) 1525e88f27b3Smrg usage(argv[0]); 1526e88f27b3Smrg 1527e88f27b3Smrg prop_count++; 1528e88f27b3Smrg break; 152918210155Smrg default: 153018210155Smrg usage(argv[0]); 153118210155Smrg break; 153218210155Smrg } 153318210155Smrg } 153418210155Smrg 1535e88f27b3Smrg if (!args) 1536e88f27b3Smrg encoders = connectors = crtcs = planes = framebuffers = 1; 153718210155Smrg 1538e88f27b3Smrg if (module) { 1539e88f27b3Smrg dev.fd = drmOpen(module, device); 1540e88f27b3Smrg if (dev.fd < 0) { 1541e88f27b3Smrg fprintf(stderr, "failed to open device '%s'.\n", module); 1542e88f27b3Smrg return 1; 1543e88f27b3Smrg } 1544e88f27b3Smrg } else { 1545e88f27b3Smrg for (i = 0; i < ARRAY_SIZE(modules); i++) { 1546e88f27b3Smrg printf("trying to open device '%s'...", modules[i]); 1547e88f27b3Smrg dev.fd = drmOpen(modules[i], device); 1548e88f27b3Smrg if (dev.fd < 0) { 1549e88f27b3Smrg printf("failed.\n"); 1550e88f27b3Smrg } else { 1551e88f27b3Smrg printf("success.\n"); 1552e88f27b3Smrg break; 1553e88f27b3Smrg } 1554e88f27b3Smrg } 1555e88f27b3Smrg 1556e88f27b3Smrg if (dev.fd < 0) { 1557e88f27b3Smrg fprintf(stderr, "no device found.\n"); 1558e88f27b3Smrg return 1; 155918210155Smrg } 156018210155Smrg } 156118210155Smrg 1562e88f27b3Smrg if (test_vsync && !page_flipping_supported()) { 156322944501Smrg fprintf(stderr, "page flipping not supported by drm.\n"); 156422944501Smrg return -1; 156522944501Smrg } 156622944501Smrg 1567e88f27b3Smrg if (test_vsync && !count) { 1568e88f27b3Smrg fprintf(stderr, "page flipping requires at least one -s option.\n"); 156918210155Smrg return -1; 157018210155Smrg } 157118210155Smrg 1572a7d7de1eSmrg if (test_cursor && !cursor_supported()) { 1573a7d7de1eSmrg fprintf(stderr, "hw cursor not supported by drm.\n"); 1574a7d7de1eSmrg return -1; 1575a7d7de1eSmrg } 1576a7d7de1eSmrg 1577e88f27b3Smrg dev.resources = get_resources(&dev); 1578e88f27b3Smrg if (!dev.resources) { 1579e88f27b3Smrg drmClose(dev.fd); 158018210155Smrg return 1; 158118210155Smrg } 158218210155Smrg 1583e88f27b3Smrg#define dump_resource(dev, res) if (res) dump_##res(dev) 1584e88f27b3Smrg 1585e88f27b3Smrg dump_resource(&dev, encoders); 1586e88f27b3Smrg dump_resource(&dev, connectors); 1587e88f27b3Smrg dump_resource(&dev, crtcs); 1588e88f27b3Smrg dump_resource(&dev, planes); 1589e88f27b3Smrg dump_resource(&dev, framebuffers); 1590e88f27b3Smrg 1591e88f27b3Smrg for (i = 0; i < prop_count; ++i) 1592e88f27b3Smrg set_property(&dev, &prop_args[i]); 1593e88f27b3Smrg 1594e88f27b3Smrg if (count || plane_count) { 1595e88f27b3Smrg ret = kms_create(dev.fd, &dev.kms); 1596e88f27b3Smrg if (ret) { 1597e88f27b3Smrg fprintf(stderr, "failed to create kms driver: %s\n", 1598e88f27b3Smrg strerror(-ret)); 1599e88f27b3Smrg return 1; 1600e88f27b3Smrg } 1601e88f27b3Smrg 1602e88f27b3Smrg if (count) 1603e88f27b3Smrg set_mode(&dev, pipe_args, count); 1604e88f27b3Smrg 1605e88f27b3Smrg if (plane_count) 1606e88f27b3Smrg set_planes(&dev, plane_args, plane_count); 1607e88f27b3Smrg 1608a7d7de1eSmrg if (test_cursor) 1609a7d7de1eSmrg set_cursors(&dev, pipe_args, count); 1610a7d7de1eSmrg 1611e88f27b3Smrg if (test_vsync) 1612e88f27b3Smrg test_page_flip(&dev, pipe_args, count); 1613e88f27b3Smrg 1614e88f27b3Smrg if (drop_master) 1615e88f27b3Smrg drmDropMaster(dev.fd); 1616e88f27b3Smrg 1617a7d7de1eSmrg getchar(); 1618a7d7de1eSmrg 1619a7d7de1eSmrg if (test_cursor) 1620a7d7de1eSmrg clear_cursors(&dev); 1621a7d7de1eSmrg 1622e88f27b3Smrg kms_bo_destroy(&dev.mode.bo); 1623e88f27b3Smrg kms_destroy(&dev.kms); 162418210155Smrg } 162518210155Smrg 1626e88f27b3Smrg free_resources(dev.resources); 162718210155Smrg 162818210155Smrg return 0; 162918210155Smrg} 1630