blob: 6b2e56825ea3f82d26ce2f974560d92ddac61f2c [file] [log] [blame]
Dominik Behr83010f82016-03-18 18:43:08 -07001/*
2 * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7#include <errno.h>
8#include <fcntl.h>
9#include <stdbool.h>
10#include <stddef.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <sys/mman.h>
15#include <time.h>
16#include <unistd.h>
17
18#include "drm.h"
Dominik Behrd2cc4d22016-01-29 17:31:52 -080019#include "input.h"
Dominik Behr83010f82016-03-18 18:43:08 -070020#include "util.h"
21
Dominik Behrda3c0102016-06-08 15:05:38 -070022static drm_t* g_drm = NULL;
Dominik Behr83010f82016-03-18 18:43:08 -070023
Daniele Castagna3ccfd382017-02-02 19:51:00 -050024static int32_t crtc_planes_num(drm_t* drm, int32_t crtc_index)
25{
26 drmModePlanePtr plane;
27 int32_t planes_num = 0;
28 drmModePlaneResPtr plane_resources = drmModeGetPlaneResources(drm->fd);
Dominik Behr57b5c722018-08-08 18:52:31 -070029
30 if (!plane_resources)
31 return 1; /* Just pretend there is one plane. */
32
Daniele Castagna3ccfd382017-02-02 19:51:00 -050033 for (uint32_t p = 0; p < plane_resources->count_planes; p++) {
34 plane = drmModeGetPlane(drm->fd, plane_resources->planes[p]);
35
36 if (plane->possible_crtcs & (1 << crtc_index))
37 planes_num++;
38
39 drmModeFreePlane(plane);
40 }
41 drmModeFreePlaneResources(plane_resources);
42 return planes_num;
43}
44
Dominik Behr57b5c722018-08-08 18:52:31 -070045static bool get_connector_path(drm_t* drm, uint32_t connector_id, uint32_t* ret_encoder_id, uint32_t* ret_crtc_id)
Dominik Behr83010f82016-03-18 18:43:08 -070046{
Dominik Behr57b5c722018-08-08 18:52:31 -070047 drmModeConnector* connector = drmModeGetConnector(drm->fd, connector_id);
Dominik Behr83010f82016-03-18 18:43:08 -070048 drmModeEncoder* encoder;
Dominik Behr83010f82016-03-18 18:43:08 -070049
Dominik Behr57b5c722018-08-08 18:52:31 -070050 if (!connector)
51 return false; /* Error. */
Dominik Behr83010f82016-03-18 18:43:08 -070052
Dominik Behr57b5c722018-08-08 18:52:31 -070053 if (ret_encoder_id)
54 *ret_encoder_id = connector->encoder_id;
55 if (!connector->encoder_id) {
56 drmModeFreeConnector(connector);
57 if (ret_crtc_id)
58 *ret_crtc_id = 0;
59 return true; /* Not connected. */
Dominik Behr83010f82016-03-18 18:43:08 -070060 }
61
Dominik Behr57b5c722018-08-08 18:52:31 -070062 encoder = drmModeGetEncoder(drm->fd, connector->encoder_id);
63 if (!encoder) {
64 if (ret_crtc_id)
65 *ret_crtc_id = 0;
66 drmModeFreeConnector(connector);
67 return false; /* Error. */
68 }
69
70 if (ret_crtc_id)
71 *ret_crtc_id = encoder->crtc_id;
72
73 drmModeFreeEncoder(encoder);
74 drmModeFreeConnector(connector);
75 return true; /* Connected. */
76}
77
78/* Find CRTC with most planes for given connector_id. */
79static bool find_crtc_for_connector(drm_t* drm, uint32_t connector_id, uint32_t* ret_crtc_id)
80{
81 int enc;
82 int32_t crtc_id = -1;
83 int32_t max_crtc_planes = -1;
84 drmModeConnector* connector = drmModeGetConnector(drm->fd, connector_id);
85
86 if (!connector)
87 return false;
88
89 for (enc = 0; enc < connector->count_encoders; enc++) {
90 int crtc;
91 drmModeEncoder* encoder = drmModeGetEncoder(drm->fd, connector->encoders[enc]);
Dominik Behr83010f82016-03-18 18:43:08 -070092
93 if (encoder) {
Dominik Behr57b5c722018-08-08 18:52:31 -070094 for (crtc = 0; crtc < drm->resources->count_crtcs; crtc++) {
95 int32_t crtc_planes;
96
97 if (!(encoder->possible_crtcs & (1 << crtc)))
Dominik Behr83010f82016-03-18 18:43:08 -070098 continue;
Daniele Castagna3ccfd382017-02-02 19:51:00 -050099
Dominik Behr57b5c722018-08-08 18:52:31 -0700100 crtc_planes = crtc_planes_num(drm, crtc);
Daniele Castagna3ccfd382017-02-02 19:51:00 -0500101 if (max_crtc_planes < crtc_planes) {
Dominik Behr57b5c722018-08-08 18:52:31 -0700102 crtc_id = drm->resources->crtcs[crtc];
Daniele Castagna3ccfd382017-02-02 19:51:00 -0500103 max_crtc_planes = crtc_planes;
104 }
Dominik Behr83010f82016-03-18 18:43:08 -0700105 }
Dominik Behr57b5c722018-08-08 18:52:31 -0700106
Daniele Castagna3ccfd382017-02-02 19:51:00 -0500107 drmModeFreeEncoder(encoder);
Dominik Behr57b5c722018-08-08 18:52:31 -0700108 if (crtc_id != -1) {
109 if (ret_crtc_id)
110 *ret_crtc_id = crtc_id;
111 drmModeFreeConnector(connector);
112 return true;
113 }
Dominik Behr83010f82016-03-18 18:43:08 -0700114 }
115 }
116
Dominik Behr57b5c722018-08-08 18:52:31 -0700117 drmModeFreeConnector(connector);
118 return false;
Dominik Behr83010f82016-03-18 18:43:08 -0700119}
120
121static int drm_is_primary_plane(drm_t* drm, uint32_t plane_id)
122{
123 uint32_t p;
124 bool found = false;
125 int ret = -1;
126
127 drmModeObjectPropertiesPtr props;
128 props = drmModeObjectGetProperties(drm->fd,
129 plane_id,
130 DRM_MODE_OBJECT_PLANE);
131 if (!props) {
132 LOG(ERROR, "Unable to get plane properties: %m");
133 return -1;
134 }
135
136 for (p = 0; p < props->count_props && !found; p++) {
137 drmModePropertyPtr prop;
138 prop = drmModeGetProperty(drm->fd, props->props[p]);
139 if (prop) {
140 if (strcmp("type", prop->name) == 0) {
141 found = true;
142 ret = (props->prop_values[p] == DRM_PLANE_TYPE_PRIMARY);
143 }
144 drmModeFreeProperty(prop);
145 }
146 }
147
148 drmModeFreeObjectProperties(props);
149
150 return ret;
151}
152
Dominik Behrb1abcba2016-04-14 14:57:21 -0700153/* Disable all planes except for primary on crtc we use. */
Dominik Behr57b5c722018-08-08 18:52:31 -0700154static void drm_disable_non_primary_planes(drm_t* drm, uint32_t console_crtc_id)
Dominik Behr83010f82016-03-18 18:43:08 -0700155{
156 int ret;
157
158 if (!drm->plane_resources)
159 return;
160
161 for (uint32_t p = 0; p < drm->plane_resources->count_planes; p++) {
162 drmModePlanePtr plane;
163 plane = drmModeGetPlane(drm->fd,
164 drm->plane_resources->planes[p]);
165 if (plane) {
166 int primary = drm_is_primary_plane(drm, plane->plane_id);
Dominik Behr57b5c722018-08-08 18:52:31 -0700167 if (!(plane->crtc_id == console_crtc_id && primary != 0)) {
Dominik Behr83010f82016-03-18 18:43:08 -0700168 ret = drmModeSetPlane(drm->fd, plane->plane_id, plane->crtc_id,
169 0, 0,
170 0, 0,
171 0, 0,
172 0, 0,
173 0, 0);
174 if (ret) {
Dominik Behr57b5c722018-08-08 18:52:31 -0700175 LOG(WARNING, "Unable to disable plane:%d %m", plane->plane_id);
Dominik Behr83010f82016-03-18 18:43:08 -0700176 }
177 }
178 drmModeFreePlane(plane);
179 }
180 }
181}
182
183static bool drm_is_internal(unsigned type)
184{
185 unsigned t;
186 unsigned kInternalConnectors[] = {
187 DRM_MODE_CONNECTOR_LVDS,
188 DRM_MODE_CONNECTOR_eDP,
189 DRM_MODE_CONNECTOR_DSI,
190 };
191 for (t = 0; t < ARRAY_SIZE(kInternalConnectors); t++)
192 if (type == kInternalConnectors[t])
193 return true;
194 return false;
195}
196
197static drmModeConnector* find_first_connected_connector(drm_t* drm, bool internal, bool external)
198{
199 for (int i = 0; i < drm->resources->count_connectors; i++) {
200 drmModeConnector* connector;
201
202 connector = drmModeGetConnector(drm->fd, drm->resources->connectors[i]);
203 if (connector) {
204 bool is_internal = drm_is_internal(connector->connector_type);
205 if (!internal && is_internal)
206 continue;
207 if (!external && !is_internal)
208 continue;
209 if ((connector->count_modes > 0) &&
210 (connector->connection == DRM_MODE_CONNECTED))
211 return connector;
212
213 drmModeFreeConnector(connector);
214 }
215 }
216 return NULL;
217}
218
Dominik Behr57b5c722018-08-08 18:52:31 -0700219static bool find_main_monitor(drm_t* drm)
Dominik Behr83010f82016-03-18 18:43:08 -0700220{
221 int modes;
Dominik Behr57b5c722018-08-08 18:52:31 -0700222 uint32_t console_crtc_id = 0;
Dominik Behrd2cc4d22016-01-29 17:31:52 -0800223 int lid_state = input_check_lid_state();
Dominik Behr83010f82016-03-18 18:43:08 -0700224 drmModeConnector* main_monitor_connector = NULL;
225
Dominik Behr57b5c722018-08-08 18:52:31 -0700226 drm->console_connector_id = 0;
227
Dominik Behr83010f82016-03-18 18:43:08 -0700228 /*
229 * Find the LVDS/eDP/DSI connectors. Those are the main screens.
230 */
Dominik Behrd2cc4d22016-01-29 17:31:52 -0800231 if (lid_state <= 0)
232 main_monitor_connector = find_first_connected_connector(drm, true, false);
Dominik Behr83010f82016-03-18 18:43:08 -0700233
234 /*
235 * Now try external connectors.
236 */
237 if (!main_monitor_connector)
238 main_monitor_connector =
239 find_first_connected_connector(drm, false, true);
240
241 /*
242 * If we still didn't find a connector, give up and return.
243 */
244 if (!main_monitor_connector)
Dominik Behr57b5c722018-08-08 18:52:31 -0700245 return false;
Dominik Behr83010f82016-03-18 18:43:08 -0700246
Dominik Behr57b5c722018-08-08 18:52:31 -0700247 if (!main_monitor_connector->count_modes)
248 return false;
249
250 drm->console_connector_id = main_monitor_connector->connector_id;
251 drm->console_connector_internal = drm_is_internal(main_monitor_connector->connector_type);
252 drm->console_mmWidth = main_monitor_connector->mmWidth;
253 drm->console_mmHeight = main_monitor_connector->mmHeight;
254
Dominik Behr83010f82016-03-18 18:43:08 -0700255 for (modes = 0; modes < main_monitor_connector->count_modes; modes++) {
256 if (main_monitor_connector->modes[modes].type &
257 DRM_MODE_TYPE_PREFERRED) {
Dominik Behr57b5c722018-08-08 18:52:31 -0700258 drm->console_mode_info = main_monitor_connector->modes[modes];
Dominik Behr83010f82016-03-18 18:43:08 -0700259 break;
260 }
261 }
Dominik Behr57b5c722018-08-08 18:52:31 -0700262 /* If there was no preferred mode use first one. */
263 if (modes == main_monitor_connector->count_modes)
264 drm->console_mode_info = main_monitor_connector->modes[0];
Dominik Behr83010f82016-03-18 18:43:08 -0700265
Dominik Behr57b5c722018-08-08 18:52:31 -0700266 drmModeFreeConnector(main_monitor_connector);
267
268 get_connector_path(drm, drm->console_connector_id, NULL, &console_crtc_id);
269
270 if (!console_crtc_id)
271 /* No existing path, find one. */
272 find_crtc_for_connector(drm, drm->console_connector_id, &console_crtc_id);
273
274 if (!console_crtc_id)
275 /* Cannot find CRTC for connector. We will not be able to use it. */
276 return false;
277
278 return true;
Dominik Behr83010f82016-03-18 18:43:08 -0700279}
280
Dominik Behr6e0f6fd2016-12-02 17:54:08 -0800281static void drm_clear_rmfb(drm_t* drm)
282{
283 if (drm->delayed_rmfb_fb_id) {
284 drmModeRmFB(drm->fd, drm->delayed_rmfb_fb_id);
285 drm->delayed_rmfb_fb_id = 0;
286 }
287}
288
Dominik Behr83010f82016-03-18 18:43:08 -0700289static void drm_fini(drm_t* drm)
290{
291 if (!drm)
292 return;
293
294 if (drm->fd >= 0) {
Dominik Behr6e0f6fd2016-12-02 17:54:08 -0800295 drm_clear_rmfb(drm);
296
Dominik Behr83010f82016-03-18 18:43:08 -0700297 if (drm->plane_resources) {
298 drmModeFreePlaneResources(drm->plane_resources);
299 drm->plane_resources = NULL;
300 }
301
302 if (drm->resources) {
303 drmModeFreeResources(drm->resources);
304 drm->resources = NULL;
305 }
306
307 drmClose(drm->fd);
308 drm->fd = -1;
309 }
310
311 free(drm);
312}
313
314static bool drm_equal(drm_t* l, drm_t* r)
315{
Dominik Behrd4d56272016-03-31 18:55:17 -0700316 if (!l && !r)
317 return true;
318 if ((!l && r) || (l && !r))
319 return false;
Dominik Behr83010f82016-03-18 18:43:08 -0700320
Dominik Behr57b5c722018-08-08 18:52:31 -0700321 if (l->console_connector_id != r->console_connector_id)
Dominik Behr83010f82016-03-18 18:43:08 -0700322 return false;
Dominik Behr83010f82016-03-18 18:43:08 -0700323 return true;
324}
325
326static int drm_score(drm_t* drm)
327{
328 drmVersionPtr version;
329 int score = 0;
330
331 if (!drm)
332 return -1000000000;
333
Dominik Behr57b5c722018-08-08 18:52:31 -0700334 if (!drm->console_connector_id)
Dominik Behr83010f82016-03-18 18:43:08 -0700335 return -1000000000;
336
Dominik Behr57b5c722018-08-08 18:52:31 -0700337 if (drm->console_connector_internal)
Dominik Behr83010f82016-03-18 18:43:08 -0700338 score++;
339
340 version = drmGetVersion(drm->fd);
341 if (version) {
Dominik Behrb1abcba2016-04-14 14:57:21 -0700342 /* We would rather use any driver besides UDL. */
Dominik Behr83010f82016-03-18 18:43:08 -0700343 if (strcmp("udl", version->name) == 0)
344 score--;
345 if (strcmp("evdi", version->name) == 0)
346 score--;
Dominik Behrb1abcba2016-04-14 14:57:21 -0700347 /* VGEM should be ignored because it has no displays, but lets make sure. */
Dominik Behr83010f82016-03-18 18:43:08 -0700348 if (strcmp("vgem", version->name) == 0)
349 score -= 1000000;
350 drmFreeVersion(version);
351 }
352 return score;
353}
354
Dominik Behrb1abcba2016-04-14 14:57:21 -0700355/*
356 * Scan and find best DRM object to display frecon on.
357 * This object should be created with DRM master, and we will keep master till
358 * first mode set or explicit drop master.
359 */
Dominik Behr83010f82016-03-18 18:43:08 -0700360drm_t* drm_scan(void)
361{
362 unsigned i;
363 char* dev_name;
364 int ret;
365 drm_t *best_drm = NULL;
366
367 for (i = 0; i < DRM_MAX_MINOR; i++) {
368 drm_t* drm = calloc(1, sizeof(drm_t));
369
370 if (!drm)
371 return NULL;
372
Dominik Behr815dc3d2016-04-19 16:59:39 -0700373try_open_again:
Dominik Behr83010f82016-03-18 18:43:08 -0700374 ret = asprintf(&dev_name, DRM_DEV_NAME, DRM_DIR_NAME, i);
375 if (ret < 0) {
376 drm_fini(drm);
377 continue;
378 }
Dominik Behr83010f82016-03-18 18:43:08 -0700379 drm->fd = open(dev_name, O_RDWR, 0);
380 free(dev_name);
381 if (drm->fd < 0) {
382 drm_fini(drm);
383 continue;
384 }
Dominik Behr815dc3d2016-04-19 16:59:39 -0700385 /* if we have master this should succeed */
386 ret = drmSetMaster(drm->fd);
387 if (ret != 0) {
388 drmClose(drm->fd);
389 drm->fd = -1;
390 usleep(100*1000);
391 goto try_open_again;
392 }
Dominik Behr83010f82016-03-18 18:43:08 -0700393
Dominik Behr57b5c722018-08-08 18:52:31 -0700394 /* Set universal planes cap if possible. Ignore any errors. */
395 drmSetClientCap(drm->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
396
Dominik Behr83010f82016-03-18 18:43:08 -0700397 drm->resources = drmModeGetResources(drm->fd);
398 if (!drm->resources) {
399 drm_fini(drm);
400 continue;
401 }
402
Dominik Behrb1abcba2016-04-14 14:57:21 -0700403 /* Expect at least one crtc so we do not try to run on VGEM. */
Dominik Behr83010f82016-03-18 18:43:08 -0700404 if (drm->resources->count_crtcs == 0 || drm->resources->count_connectors == 0) {
405 drm_fini(drm);
406 continue;
407 }
408
Dominik Behr83010f82016-03-18 18:43:08 -0700409 drm->plane_resources = drmModeGetPlaneResources(drm->fd);
Dominik Behr57b5c722018-08-08 18:52:31 -0700410
411 if (!find_main_monitor(drm)) {
412 drm_fini(drm);
413 continue;
414 }
415
Dominik Behr83010f82016-03-18 18:43:08 -0700416 drm->refcount = 1;
417
418 if (drm_score(drm) > drm_score(best_drm)) {
419 drm_fini(best_drm);
420 best_drm = drm;
Dominik Behr45896022016-11-10 14:12:59 -0800421 } else {
422 drm_fini(drm);
Dominik Behr83010f82016-03-18 18:43:08 -0700423 }
424 }
425
426 if (best_drm) {
427 drmVersionPtr version;
428 version = drmGetVersion(best_drm->fd);
429 if (version) {
430 LOG(INFO,
431 "Frecon using drm driver %s, version %d.%d, date(%s), desc(%s)",
432 version->name,
433 version->version_major,
434 version->version_minor,
435 version->date,
436 version->desc);
437 drmFreeVersion(version);
438 }
Dominik Behr83010f82016-03-18 18:43:08 -0700439 }
440
441 return best_drm;
442}
443
444void drm_set(drm_t* drm_)
445{
Dominik Behrda3c0102016-06-08 15:05:38 -0700446 if (g_drm) {
447 drm_delref(g_drm);
448 g_drm = NULL;
Dominik Behr83010f82016-03-18 18:43:08 -0700449 }
Dominik Behrda3c0102016-06-08 15:05:38 -0700450 g_drm = drm_;
Dominik Behr83010f82016-03-18 18:43:08 -0700451}
452
453void drm_close(void)
454{
Dominik Behrda3c0102016-06-08 15:05:38 -0700455 if (g_drm) {
456 drm_delref(g_drm);
457 g_drm = NULL;
Dominik Behr83010f82016-03-18 18:43:08 -0700458 }
459}
460
Dominik Behrb1abcba2016-04-14 14:57:21 -0700461void drm_delref(drm_t* drm)
Dominik Behr83010f82016-03-18 18:43:08 -0700462{
Dominik Behrd4d56272016-03-31 18:55:17 -0700463 if (!drm)
464 return;
Dominik Behr83010f82016-03-18 18:43:08 -0700465 if (drm->refcount) {
466 drm->refcount--;
467 } else {
468 LOG(ERROR, "Imbalanced drm_close()");
469 }
470 if (drm->refcount) {
471 return;
472 }
473
474 drm_fini(drm);
475}
476
477drm_t* drm_addref(void)
478{
Dominik Behrda3c0102016-06-08 15:05:38 -0700479 if (g_drm) {
480 g_drm->refcount++;
481 return g_drm;
Dominik Behr83010f82016-03-18 18:43:08 -0700482 }
483
484 return NULL;
485}
486
Dominik Behrda3c0102016-06-08 15:05:38 -0700487int drm_dropmaster(drm_t* drm)
Dominik Behrb1abcba2016-04-14 14:57:21 -0700488{
Dominik Behrda3c0102016-06-08 15:05:38 -0700489 int ret = 0;
490
491 if (!drm)
492 drm = g_drm;
493 if (drm)
494 ret = drmDropMaster(drm->fd);
495 return ret;
496}
497
498int drm_setmaster(drm_t* drm)
499{
500 int ret = 0;
501
502 if (!drm)
503 drm = g_drm;
504 if (drm)
505 ret = drmSetMaster(drm->fd);
506 return ret;
Dominik Behrb1abcba2016-04-14 14:57:21 -0700507}
508
Dominik Behr83010f82016-03-18 18:43:08 -0700509/*
Dominik Behrb1abcba2016-04-14 14:57:21 -0700510 * Returns true if connector/crtc/driver have changed and framebuffer object have to be re-created.
Dominik Behr83010f82016-03-18 18:43:08 -0700511 */
512bool drm_rescan(void)
513{
514 drm_t* ndrm;
515
Dominik Behrb1abcba2016-04-14 14:57:21 -0700516 /* In case we had master, drop master so the newly created object could have it. */
Dominik Behrda3c0102016-06-08 15:05:38 -0700517 drm_dropmaster(g_drm);
Dominik Behr83010f82016-03-18 18:43:08 -0700518 ndrm = drm_scan();
519 if (ndrm) {
Dominik Behrda3c0102016-06-08 15:05:38 -0700520 if (drm_equal(ndrm, g_drm)) {
Dominik Behr83010f82016-03-18 18:43:08 -0700521 drm_fini(ndrm);
Dominik Behrda3c0102016-06-08 15:05:38 -0700522 /* Regain master we dropped. */
523 drm_setmaster(g_drm);
Dominik Behr83010f82016-03-18 18:43:08 -0700524 } else {
Dominik Behrda3c0102016-06-08 15:05:38 -0700525 drm_delref(g_drm);
526 g_drm = ndrm;
Dominik Behr83010f82016-03-18 18:43:08 -0700527 return true;
528 }
529 } else {
Dominik Behrda3c0102016-06-08 15:05:38 -0700530 if (g_drm) {
531 drm_delref(g_drm); /* No usable monitor/drm object. */
532 g_drm = NULL;
Dominik Behr83010f82016-03-18 18:43:08 -0700533 return true;
534 }
535 }
536 return false;
537}
538
539bool drm_valid(drm_t* drm) {
Dominik Behr57b5c722018-08-08 18:52:31 -0700540 return drm && drm->fd >= 0 && drm->resources && drm->console_connector_id;
Dominik Behr83010f82016-03-18 18:43:08 -0700541}
542
543int32_t drm_setmode(drm_t* drm, uint32_t fb_id)
544{
Dominik Behr57b5c722018-08-08 18:52:31 -0700545 int conn;
Dominik Behr83010f82016-03-18 18:43:08 -0700546 int32_t ret;
Dominik Behr57b5c722018-08-08 18:52:31 -0700547 uint32_t existing_console_crtc_id = 0;
Dominik Behr51a4da52016-07-28 14:18:48 -0700548
Dominik Behr57b5c722018-08-08 18:52:31 -0700549 get_connector_path(drm, drm->console_connector_id, NULL, &existing_console_crtc_id);
Dominik Behr51a4da52016-07-28 14:18:48 -0700550
Dominik Behr57b5c722018-08-08 18:52:31 -0700551 /* Loop through all the connectors, disable ones that are configured and set video mode on console connector. */
552 for (conn = 0; conn < drm->resources->count_connectors; conn++) {
553 uint32_t connector_id = drm->resources->connectors[conn];
Dominik Behr83010f82016-03-18 18:43:08 -0700554
Dominik Behr57b5c722018-08-08 18:52:31 -0700555 if (connector_id == drm->console_connector_id) {
556 uint32_t console_crtc_id = 0;
557
558 if (existing_console_crtc_id)
559 console_crtc_id = existing_console_crtc_id;
560 else {
561 find_crtc_for_connector(drm, connector_id, &console_crtc_id);
562
563 if (!console_crtc_id) {
564 LOG(ERROR, "Could not get console crtc for connector:%d in modeset.\n", drm->console_connector_id);
565 return -ENOENT;
566 }
567 }
568
569 ret = drmModeSetCrtc(drm->fd, console_crtc_id,
570 fb_id,
571 0, 0, // x,y
572 &drm->console_connector_id,
573 1, // connector_count
574 &drm->console_mode_info); // mode
575
576 if (ret) {
577 LOG(ERROR, "Unable to set crtc:%d connector:%d %m", console_crtc_id, drm->console_connector_id);
578 return ret;
579 }
580
581 ret = drmModeSetCursor(drm->fd, console_crtc_id,
582 0, 0, 0);
583
584 if (ret)
585 LOG(ERROR, "Unable to hide cursor on crtc:%d %m.", console_crtc_id);
586
587 drm_disable_non_primary_planes(drm, console_crtc_id);
588
589 } else {
590 uint32_t crtc_id = 0;
591
592 get_connector_path(drm, connector_id, NULL, &crtc_id);
593 if (!crtc_id)
594 /* This connector is not configured, skip. */
595 continue;
596
597 if (existing_console_crtc_id && existing_console_crtc_id == crtc_id)
598 /* This connector is mirroring from the same CRTC as console. It will be turned off when console is set. */
599 continue;
600
601 ret = drmModeSetCrtc(drm->fd, crtc_id, 0, // buffer_id
602 0, 0, // x,y
603 NULL, // connectors
604 0, // connector_count
605 NULL); // mode
606 if (ret)
607 LOG(ERROR, "Unable to disable crtc %d: %m", crtc_id);
608 }
Dominik Behr83010f82016-03-18 18:43:08 -0700609 }
610
Dominik Behr6e0f6fd2016-12-02 17:54:08 -0800611 drm_clear_rmfb(drm);
Dominik Behr57b5c722018-08-08 18:52:31 -0700612 /* LOG(INFO, "TIMING: Console switch modeset finished."); */
Dominik Behr83010f82016-03-18 18:43:08 -0700613 return ret;
614}
615
Dominik Behr6e0f6fd2016-12-02 17:54:08 -0800616/*
617 * Delayed rmfb(). We want to keep fb at least till after next modeset
618 * so our transitions are cleaner (e.g. when recreating term after exitin
619 * shell). Also it keeps fb around till Chrome starts.
620 */
621void drm_rmfb(drm_t* drm, uint32_t fb_id)
622{
623 drm_clear_rmfb(drm);
624 drm->delayed_rmfb_fb_id = fb_id;
625}
626
Dominik Behr83010f82016-03-18 18:43:08 -0700627bool drm_read_edid(drm_t* drm)
628{
Dominik Behr57b5c722018-08-08 18:52:31 -0700629 drmModeConnector* console_connector;
Dominik Behr83010f82016-03-18 18:43:08 -0700630 if (drm->edid_found) {
631 return true;
632 }
633
Dominik Behr57b5c722018-08-08 18:52:31 -0700634 console_connector = drmModeGetConnector(drm->fd, drm->console_connector_id);
635
636 if (!console_connector)
637 return false;
638
639 for (int i = 0; i < console_connector->count_props; i++) {
Dominik Behr83010f82016-03-18 18:43:08 -0700640 drmModePropertyPtr prop;
641 drmModePropertyBlobPtr blob_ptr;
Dominik Behr57b5c722018-08-08 18:52:31 -0700642 prop = drmModeGetProperty(drm->fd, console_connector->props[i]);
Dominik Behr83010f82016-03-18 18:43:08 -0700643 if (prop) {
644 if (strcmp(prop->name, "EDID") == 0) {
645 blob_ptr = drmModeGetPropertyBlob(drm->fd,
Dominik Behr57b5c722018-08-08 18:52:31 -0700646 console_connector->prop_values[i]);
Dominik Behr83010f82016-03-18 18:43:08 -0700647 if (blob_ptr) {
648 memcpy(&drm->edid, blob_ptr->data, EDID_SIZE);
649 drmModeFreePropertyBlob(blob_ptr);
Dominik Behr57b5c722018-08-08 18:52:31 -0700650 drmModeFreeConnector(console_connector);
Dominik Behr83010f82016-03-18 18:43:08 -0700651 return (drm->edid_found = true);
652 }
653 }
654 }
655 }
656
Dominik Behr57b5c722018-08-08 18:52:31 -0700657 drmModeFreeConnector(console_connector);
Dominik Behr83010f82016-03-18 18:43:08 -0700658 return false;
659}
660
661uint32_t drm_gethres(drm_t* drm)
662{
Dominik Behr57b5c722018-08-08 18:52:31 -0700663 return drm->console_mode_info.hdisplay;
Dominik Behr83010f82016-03-18 18:43:08 -0700664}
665
666uint32_t drm_getvres(drm_t* drm)
667{
Dominik Behr57b5c722018-08-08 18:52:31 -0700668 return drm->console_mode_info.vdisplay;
Dominik Behr83010f82016-03-18 18:43:08 -0700669}