blob: ded7b0f66d622841f7977719005ba1af23dff49e [file] [log] [blame]
Sean Paule0c4c3d2015-01-20 16:56:04 -05001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "hwcomposer-drm"
18
19#include <fcntl.h>
20#include <errno.h>
21#include <sys/param.h>
Sean Paul9aa5ad32015-01-22 15:47:54 -050022#include <sys/resource.h>
23#include <pthread.h>
Sean Paul9b1bb842015-01-23 01:11:58 -050024#include <queue>
Sean Paule0c4c3d2015-01-20 16:56:04 -050025
26#include <cutils/log.h>
27
28#include <xf86drm.h>
29#include <xf86drmMode.h>
Sean Paule0c4c3d2015-01-20 16:56:04 -050030
31#include <hardware/hardware.h>
32#include <hardware/hwcomposer.h>
33
Sean Paul9aa5ad32015-01-22 15:47:54 -050034#include <sync/sync.h>
35
Sean Paulcd36a9e2015-01-22 18:01:18 -050036#include "drm_hwcomposer.h"
Sean Paule0c4c3d2015-01-20 16:56:04 -050037
38#define ARRAY_SIZE(arr) (int)(sizeof(arr) / sizeof((arr)[0]))
39
40#define HWCOMPOSER_DRM_DEVICE "/dev/dri/card0"
41#define MAX_NUM_DISPLAYS 3
42#define UM_PER_INCH 25400
43
44static const uint32_t panel_types[] = {
45 DRM_MODE_CONNECTOR_LVDS,
46 DRM_MODE_CONNECTOR_eDP,
47 DRM_MODE_CONNECTOR_DSI,
48};
49
Sean Paul9aa5ad32015-01-22 15:47:54 -050050struct hwc_worker {
51 pthread_t thread;
52 pthread_mutex_t lock;
53 pthread_cond_t cond;
54 bool exit;
55};
56
Sean Paule0c4c3d2015-01-20 16:56:04 -050057struct hwc_drm_display {
Sean Paul9aa5ad32015-01-22 15:47:54 -050058 struct hwc_context_t *ctx;
59 int display;
60
Sean Paule0c4c3d2015-01-20 16:56:04 -050061 uint32_t connector_id;
62
63 drmModeModeInfoPtr configs;
64 uint32_t num_configs;
65
66 int active_config;
67 uint32_t active_crtc;
Sean Paul9aa5ad32015-01-22 15:47:54 -050068
69 struct hwc_worker set_worker;
70
Sean Paul9b1bb842015-01-23 01:11:58 -050071 std::queue<struct hwc_drm_bo> buf_queue;
Sean Paul9aa5ad32015-01-22 15:47:54 -050072 struct hwc_drm_bo front;
Sean Paule0c4c3d2015-01-20 16:56:04 -050073};
74
75struct hwc_context_t {
76 hwc_composer_device_1_t device;
77
78 int fd;
Sean Paule0c4c3d2015-01-20 16:56:04 -050079
80 hwc_procs_t const *procs;
Sean Paulcd36a9e2015-01-22 18:01:18 -050081 struct hwc_import_context *import_ctx;
Sean Paule0c4c3d2015-01-20 16:56:04 -050082
83 struct hwc_drm_display displays[MAX_NUM_DISPLAYS];
84 int num_displays;
85};
86
87static int hwc_get_drm_display(struct hwc_context_t *ctx, int display,
88 struct hwc_drm_display **hd)
89{
90 if (display >= MAX_NUM_DISPLAYS) {
91 ALOGE("Requested display is out-of-bounds %d %d", display,
92 MAX_NUM_DISPLAYS);
93 return -EINVAL;
94 }
95 *hd = &ctx->displays[display];
96 return 0;
97}
98
99static int hwc_prepare_layer(hwc_layer_1_t *layer)
100{
101 /* TODO: We can't handle background right now, defer to sufaceFlinger */
102 if (layer->compositionType == HWC_BACKGROUND) {
103 layer->compositionType = HWC_FRAMEBUFFER;
104 ALOGV("Can't handle background layers yet");
105
106 /* TODO: Support sideband compositions */
107 } else if (layer->compositionType == HWC_SIDEBAND) {
108 layer->compositionType = HWC_FRAMEBUFFER;
109 ALOGV("Can't handle sideband content yet");
110 }
111
112 layer->hints = 0;
113
114 /* TODO: Handle cursor by setting compositionType=HWC_CURSOR_OVERLAY */
115 if (layer->flags & HWC_IS_CURSOR_LAYER) {
116 ALOGV("Can't handle async cursors yet");
117 }
118
119 /* TODO: Handle transformations */
120 if (layer->transform) {
121 ALOGV("Can't handle transformations yet");
122 }
123
124 /* TODO: Handle blending & plane alpha*/
125 if (layer->blending == HWC_BLENDING_PREMULT ||
126 layer->blending == HWC_BLENDING_COVERAGE) {
127 ALOGV("Can't handle blending yet");
128 }
129
130 /* TODO: Handle cropping & scaling */
131
132 return 0;
133}
134
135static int hwc_prepare(hwc_composer_device_1_t */* dev */, size_t num_displays,
136 hwc_display_contents_1_t** display_contents)
137{
138 int ret = 0, i, j;
139
140 /* TODO: Check flags for HWC_GEOMETRY_CHANGED */
141
142 for (i = 0; i < (int)num_displays && i < MAX_NUM_DISPLAYS; i++) {
143 for (j = 0; j < (int)display_contents[i]->numHwLayers; j++) {
144 ret = hwc_prepare_layer(
145 &display_contents[i]->hwLayers[j]);
146 if (ret) {
147 ALOGE("Failed to prepare layer %d:%d", j, i);
148 return ret;
149 }
150 }
151 }
152
153 return ret;
154}
155
Sean Paulcd36a9e2015-01-22 18:01:18 -0500156/*
157 * TODO: This hack allows us to use the importer's fd to drm to add and remove
158 * framebuffers. The reason it exists is because gralloc doesn't export its
159 * bo's, so we have to use its file descriptor to drm for some operations. Once
160 * gralloc behaves, we can remove this.
161 */
162static int hwc_get_fd_for_bo(struct hwc_context_t *ctx, struct hwc_drm_bo *bo)
163{
164 if (bo->importer_fd >= 0)
165 return bo->importer_fd;
166
167 return ctx->fd;
168}
169
Sean Paule0c4c3d2015-01-20 16:56:04 -0500170static bool hwc_mode_is_equal(drmModeModeInfoPtr a, drmModeModeInfoPtr b)
171{
172 return a->clock == b->clock &&
173 a->hdisplay == b->hdisplay &&
174 a->hsync_start == b->hsync_start &&
175 a->hsync_end == b->hsync_end &&
176 a->htotal == b->htotal &&
177 a->hskew == b->hskew &&
178 a->vdisplay == b->vdisplay &&
179 a->vsync_start == b->vsync_start &&
180 a->vsync_end == b->vsync_end &&
181 a->vtotal == b->vtotal &&
182 a->vscan == b->vscan &&
183 a->vrefresh == b->vrefresh &&
184 a->flags == b->flags &&
185 a->type == b->type &&
186 !strcmp(a->name, b->name);
187}
188
Sean Paul9aa5ad32015-01-22 15:47:54 -0500189static int hwc_modeset_required(struct hwc_drm_display *hd,
190 bool *modeset_required)
191{
192 drmModeCrtcPtr crtc;
193 drmModeModeInfoPtr m;
194
195 crtc = drmModeGetCrtc(hd->ctx->fd, hd->active_crtc);
196 if (!crtc) {
197 ALOGE("Failed to get crtc for display %d", hd->display);
198 return -ENODEV;
199 }
200
201 m = &hd->configs[hd->active_config];
202
203 /* Do a modeset if we haven't done one, or the mode has changed */
204 if (!crtc->mode_valid || !hwc_mode_is_equal(m, &crtc->mode))
205 *modeset_required = true;
206 else
207 *modeset_required = false;
208
209 drmModeFreeCrtc(crtc);
210
211 return 0;
212}
213
214static void hwc_flip_handler(int /* fd */, unsigned int /* sequence */,
215 unsigned int /* tv_sec */, unsigned int /* tv_usec */,
216 void */* user_data */)
217{
218}
219
Sean Paul9b1bb842015-01-23 01:11:58 -0500220static int hwc_flip(struct hwc_drm_display *hd, struct hwc_drm_bo *buf)
Sean Paul9aa5ad32015-01-22 15:47:54 -0500221{
222 fd_set fds;
223 drmEventContext event_context;
224 int ret;
225 bool modeset_required;
226
227 ret = hwc_modeset_required(hd, &modeset_required);
228 if (ret) {
229 ALOGE("Failed to determine if modeset is required %d", ret);
230 return ret;
231 }
232 if (modeset_required) {
Sean Paul9b1bb842015-01-23 01:11:58 -0500233 ret = drmModeSetCrtc(hd->ctx->fd, hd->active_crtc, buf->fb_id,
234 0, 0, &hd->connector_id, 1,
Sean Paul9aa5ad32015-01-22 15:47:54 -0500235 &hd->configs[hd->active_config]);
236 if (ret) {
237 ALOGE("Modeset failed for crtc %d",
238 hd->active_crtc);
239 return ret;
240 }
241 return 0;
242 }
243
244 FD_ZERO(&fds);
245 FD_SET(hd->ctx->fd, &fds);
246
247 event_context.version = DRM_EVENT_CONTEXT_VERSION;
248 event_context.page_flip_handler = hwc_flip_handler;
249
Sean Paul9b1bb842015-01-23 01:11:58 -0500250 ret = drmModePageFlip(hd->ctx->fd, hd->active_crtc, buf->fb_id,
Sean Paul9aa5ad32015-01-22 15:47:54 -0500251 DRM_MODE_PAGE_FLIP_EVENT, hd);
252 if (ret) {
253 ALOGE("Failed to flip buffer for crtc %d",
254 hd->active_crtc);
255 return ret;
256 }
257
258 do {
259 ret = select(hd->ctx->fd + 1, &fds, NULL, NULL, NULL);
260 } while (ret == -1 && errno == EINTR);
261
262 if (ret != 1) {
263 ALOGE("Failed waiting for flip to complete\n");
264 return -EINVAL;
265 }
266 drmHandleEvent(hd->ctx->fd, &event_context);
267
268 return 0;
269}
270
271static int hwc_wait_and_set(struct hwc_drm_display *hd)
272{
273 int ret;
Sean Paul9b1bb842015-01-23 01:11:58 -0500274 struct hwc_drm_bo buf = hd->buf_queue.front();
Sean Paul9aa5ad32015-01-22 15:47:54 -0500275
Sean Paul9b1bb842015-01-23 01:11:58 -0500276 ret = drmModeAddFB2(hwc_get_fd_for_bo(hd->ctx, &buf), buf.width,
277 buf.height, buf.format, buf.gem_handles, buf.pitches,
278 buf.offsets, &buf.fb_id, 0);
Sean Paul9aa5ad32015-01-22 15:47:54 -0500279 if (ret) {
280 ALOGE("could not create drm fb %d", ret);
281 return ret;
282 }
283
Sean Paul9b1bb842015-01-23 01:11:58 -0500284 if (buf.acquire_fence_fd >= 0) {
285 ret = sync_wait(buf.acquire_fence_fd, -1);
Sean Paul9aa5ad32015-01-22 15:47:54 -0500286 if (ret) {
287 ALOGE("Failed to wait for acquire %d", ret);
288 return ret;
289 }
290 }
291
Sean Paul9b1bb842015-01-23 01:11:58 -0500292 ret = hwc_flip(hd, &buf);
Sean Paul9aa5ad32015-01-22 15:47:54 -0500293 if (ret) {
294 ALOGE("Failed to perform flip\n");
295 return ret;
296 }
297
298 if (hd->front.fb_id) {
Sean Paulcd36a9e2015-01-22 18:01:18 -0500299 ret = drmModeRmFB(hwc_get_fd_for_bo(hd->ctx, &hd->front),
300 hd->front.fb_id);
Sean Paul9aa5ad32015-01-22 15:47:54 -0500301 if (ret) {
302 ALOGE("Failed to rm fb from front %d", ret);
303 return ret;
304 }
305 }
Sean Paul9b1bb842015-01-23 01:11:58 -0500306 hd->front = buf;
307 hd->buf_queue.pop();
Sean Paul9aa5ad32015-01-22 15:47:54 -0500308 return ret;
309}
310
311static void *hwc_set_worker(void *arg)
312{
313 struct hwc_drm_display *hd = (struct hwc_drm_display *)arg;
314 int ret;
315
316 setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
317
318 ret = pthread_mutex_lock(&hd->set_worker.lock);
319 if (ret) {
320 ALOGE("Failed to lock set lock %d", ret);
321 return NULL;
322 }
323
324 do {
325 ret = pthread_cond_wait(&hd->set_worker.cond,
326 &hd->set_worker.lock);
327 if (ret) {
328 ALOGE("Failed to wait on set condition %d", ret);
329 break;
330 } else if (hd->set_worker.exit) {
331 break;
332 }
333
334 ret = hwc_wait_and_set(hd);
335 if (ret)
336 ALOGE("Failed to wait and set %d", ret);
337 } while (true);
338
339 ret = pthread_mutex_unlock(&hd->set_worker.lock);
340 if (ret) {
341 ALOGE("Failed to unlock set lock %d", ret);
342 return NULL;
343 }
344
345 return NULL;
346}
347
Sean Paule0c4c3d2015-01-20 16:56:04 -0500348static int hwc_set_display(hwc_context_t *ctx, int display,
349 hwc_display_contents_1_t* display_contents)
350{
351 struct hwc_drm_display *hd = NULL;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500352 hwc_layer_1_t *layer = NULL;
Sean Paul9b1bb842015-01-23 01:11:58 -0500353 struct hwc_drm_bo buf;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500354 int ret, i;
Sean Paul9aa5ad32015-01-22 15:47:54 -0500355 uint32_t fb_id;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500356
Sean Paul9b1bb842015-01-23 01:11:58 -0500357 memset(&buf, 0, sizeof(buf));
358
Sean Paule0c4c3d2015-01-20 16:56:04 -0500359 ret = hwc_get_drm_display(ctx, display, &hd);
360 if (ret)
361 return ret;
362
363 if (!hd->active_crtc) {
364 ALOGE("There is no active crtc for display %d", display);
365 return -ENOENT;
366 }
367
368 /*
369 * TODO: We can only support one hw layer atm, so choose either the
370 * first one or the framebuffer target.
371 */
372 if (!display_contents->numHwLayers) {
373 return 0;
374 } else if (display_contents->numHwLayers == 1) {
375 layer = &display_contents->hwLayers[0];
376 } else {
377 for (i = 0; i < (int)display_contents->numHwLayers; i++) {
378 layer = &display_contents->hwLayers[i];
379 if (layer->compositionType == HWC_FRAMEBUFFER_TARGET)
380 break;
381 }
382 if (i == (int)display_contents->numHwLayers) {
383 ALOGE("Could not find a suitable layer for display %d",
384 display);
385 }
386 }
387
Sean Paul9aa5ad32015-01-22 15:47:54 -0500388 ret = pthread_mutex_lock(&hd->set_worker.lock);
Sean Paule0c4c3d2015-01-20 16:56:04 -0500389 if (ret) {
Sean Paul9aa5ad32015-01-22 15:47:54 -0500390 ALOGE("Failed to lock set lock in set() %d", ret);
391 return ret;
392 }
393
Sean Paulcd36a9e2015-01-22 18:01:18 -0500394 ret = hwc_create_bo_from_import(ctx->fd, ctx->import_ctx, layer->handle,
Sean Paul9b1bb842015-01-23 01:11:58 -0500395 &buf);
Sean Paul9aa5ad32015-01-22 15:47:54 -0500396 if (ret) {
Sean Paulcd36a9e2015-01-22 18:01:18 -0500397 ALOGE("Failed to import handle to drm bo %d", ret);
Sean Paul9aa5ad32015-01-22 15:47:54 -0500398 goto out;
399 }
Sean Paul9b1bb842015-01-23 01:11:58 -0500400 buf.acquire_fence_fd = layer->acquireFenceFd;
Sean Paul9aa5ad32015-01-22 15:47:54 -0500401 layer->releaseFenceFd = -1;
402
Sean Paul9b1bb842015-01-23 01:11:58 -0500403 hd->buf_queue.push(buf);
404
Sean Paul9aa5ad32015-01-22 15:47:54 -0500405 ret = pthread_cond_signal(&hd->set_worker.cond);
406 if (ret) {
407 ALOGE("Failed to signal set worker %d", ret);
408 goto out;
409 }
410
411 ret = pthread_mutex_unlock(&hd->set_worker.lock);
412 if (ret) {
413 ALOGE("Failed to unlock set lock in set() %d", ret);
414 return ret;
415 }
416
417 return ret;
418
Sean Paule0c4c3d2015-01-20 16:56:04 -0500419out:
Sean Paul9aa5ad32015-01-22 15:47:54 -0500420 if (pthread_mutex_unlock(&hd->set_worker.lock))
421 ALOGE("Failed to unlock set lock in set error handler");
422
Sean Paule0c4c3d2015-01-20 16:56:04 -0500423 return ret;
424}
425
426static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays,
427 hwc_display_contents_1_t** display_contents)
428{
429 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
430 int ret = 0, i;
431
432 /* TODO: Handle acquire & release fences */
433
434 for (i = 0; i < (int)num_displays && i < MAX_NUM_DISPLAYS; i++) {
435 display_contents[i]->retireFenceFd = -1; /* TODO: sync */
436
437 ret = hwc_set_display(ctx, i, display_contents[i]);
438 }
439
440 return ret;
441}
442
443static int hwc_event_control(struct hwc_composer_device_1 */* dev */,
444 int /* display */, int /* event */, int /* enabled */)
445{
446 int ret;
447
448 /* TODO */
449 return 0;
450}
451
452static int hwc_set_power_mode(struct hwc_composer_device_1* dev, int display,
453 int mode)
454{
455 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
456 struct hwc_drm_display *hd = NULL;
457 drmModeConnectorPtr c;
458 int ret, i;
459 uint32_t dpms_prop = 0;
460 uint64_t dpms_value = 0;
461
462 ret = hwc_get_drm_display(ctx, display, &hd);
463 if (ret)
464 return ret;
465
466 c = drmModeGetConnector(ctx->fd, hd->connector_id);
467 if (!c) {
468 ALOGE("Failed to get connector %d", display);
469 return -ENODEV;
470 }
471
472 for (i = 0; !dpms_prop && i < c->count_props; i++) {
473 drmModePropertyPtr p;
474
475 p = drmModeGetProperty(ctx->fd, c->props[i]);
476 if (!p)
477 continue;
478
479 if (!strcmp(p->name, "DPMS"))
480 dpms_prop = c->props[i];
481
482 drmModeFreeProperty(p);
483 }
484 if (!dpms_prop) {
485 ALOGE("Failed to get DPMS property from display %d", display);
486 ret = -ENOENT;
487 goto out;
488 }
489
490 switch(mode) {
491 case HWC_POWER_MODE_OFF:
492 dpms_value = DRM_MODE_DPMS_OFF;
493 break;
494
495 /* We can't support dozing right now, so go full on */
496 case HWC_POWER_MODE_DOZE:
497 case HWC_POWER_MODE_DOZE_SUSPEND:
498 case HWC_POWER_MODE_NORMAL:
499 dpms_value = DRM_MODE_DPMS_ON;
500 break;
501 };
502
503 ret = drmModeConnectorSetProperty(ctx->fd, c->connector_id,
504 dpms_prop, dpms_value);
505 if (ret) {
506 ALOGE("Failed to set DPMS property for display %d", display);
507 goto out;
508 }
509
510out:
511 drmModeFreeConnector(c);
512 return ret;
513}
514
515static int hwc_query(struct hwc_composer_device_1 */* dev */, int what,
516 int *value)
517{
518 switch(what) {
519 case HWC_BACKGROUND_LAYER_SUPPORTED:
520 *value = 0; /* TODO: We should do this */
521 break;
522 case HWC_VSYNC_PERIOD:
523 ALOGW("Query for deprecated vsync value, returning 60Hz");
524 *value = 1000 * 1000 * 1000 / 60;
525 break;
526 case HWC_DISPLAY_TYPES_SUPPORTED:
527 *value = HWC_DISPLAY_PRIMARY | HWC_DISPLAY_EXTERNAL;
528 break;
529 }
530 return 0;
531}
532
533static void hwc_register_procs(struct hwc_composer_device_1* dev,
534 hwc_procs_t const* procs)
535{
536 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
537
538 ctx->procs = procs;
539}
540
541static int hwc_get_display_configs(struct hwc_composer_device_1* dev,
542 int display, uint32_t* configs, size_t* numConfigs)
543{
544 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
545 struct hwc_drm_display *hd = NULL;
546 drmModeConnectorPtr c;
547 int ret = 0, i;
548
549 if (!*numConfigs)
550 return 0;
551
552 ret = hwc_get_drm_display(ctx, display, &hd);
553 if (ret)
554 return ret;
555
556 c = drmModeGetConnector(ctx->fd, hd->connector_id);
557 if (!c) {
558 ALOGE("Failed to get connector %d", display);
559 return -ENODEV;
560 }
561
562 if (hd->configs)
563 free(hd->configs);
564
565 hd->active_config = -1;
566 hd->configs = (drmModeModeInfoPtr)calloc(c->count_modes,
567 sizeof(*hd->configs));
568 if (!hd->configs) {
569 ALOGE("Failed to allocate config list for display %d", display);
570 ret = -ENOMEM;
571 hd->num_configs = 0;
572 goto out;
573 }
574
575 for (i = 0; i < c->count_modes; i++) {
576 drmModeModeInfoPtr m = &hd->configs[i];
577
578 memcpy(m, &c->modes[i], sizeof(*m));
579
580 if (i < (int)*numConfigs)
581 configs[i] = i;
582 }
583
584 hd->num_configs = c->count_modes;
585 *numConfigs = MIN(c->count_modes, *numConfigs);
586
587out:
588 drmModeFreeConnector(c);
589 return ret;
590}
591
592static int hwc_check_config_valid(struct hwc_context_t *ctx,
593 drmModeConnectorPtr connector, int display,
594 int config_idx)
595{
596 struct hwc_drm_display *hd = NULL;
597 drmModeModeInfoPtr m = NULL;
598 int ret = 0, i;
599
600 ret = hwc_get_drm_display(ctx, display, &hd);
601 if (ret)
602 return ret;
603
604 /* Make sure the requested config is still valid for the display */
605 for (i = 0; i < connector->count_modes; i++) {
606 if (hwc_mode_is_equal(&connector->modes[i],
607 &hd->configs[config_idx])) {
608 m = &hd->configs[config_idx];
609 break;
610 }
611 }
612 if (!m)
613 return -ENOENT;
614
615 return 0;
616}
617
618static int hwc_get_display_attributes(struct hwc_composer_device_1* dev,
619 int display, uint32_t config, const uint32_t* attributes,
620 int32_t* values)
621{
622 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
623 struct hwc_drm_display *hd = NULL;
624 drmModeConnectorPtr c;
625 drmModeModeInfoPtr m;
626 int ret, i;
627
628 ret = hwc_get_drm_display(ctx, display, &hd);
629 if (ret)
630 return ret;
631
632 if (config >= hd->num_configs) {
633 ALOGE("Requested config is out-of-bounds %d %d", config,
634 hd->num_configs);
635 return -EINVAL;
636 }
637
638 c = drmModeGetConnector(ctx->fd, hd->connector_id);
639 if (!c) {
640 ALOGE("Failed to get connector %d", display);
641 return -ENODEV;
642 }
643
644 ret = hwc_check_config_valid(ctx, c, display, (int)config);
645 if (ret) {
646 ALOGE("Provided config is no longer valid %u", config);
647 goto out;
648 }
649
650 m = &hd->configs[config];
651 for (i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) {
652 switch(attributes[i]) {
653 case HWC_DISPLAY_VSYNC_PERIOD:
654 values[i] = 1000 * 1000 * 1000 / m->vrefresh;
655 break;
656 case HWC_DISPLAY_WIDTH:
657 values[i] = m->hdisplay;
658 break;
659 case HWC_DISPLAY_HEIGHT:
660 values[i] = m->vdisplay;
661 break;
662 case HWC_DISPLAY_DPI_X:
663 /* Dots per 1000 inches */
664 values[i] = c->mmWidth ?
665 (m->hdisplay * UM_PER_INCH) / c->mmWidth : 0;
666 break;
667 case HWC_DISPLAY_DPI_Y:
668 /* Dots per 1000 inches */
669 values[i] = c->mmHeight ?
670 (m->vdisplay * UM_PER_INCH) / c->mmHeight : 0;
671 break;
672 }
673 }
674
675out:
676 drmModeFreeConnector(c);
677 return ret;
678}
679
680static int hwc_get_active_config(struct hwc_composer_device_1* dev, int display)
681{
682 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
683 struct hwc_drm_display *hd = NULL;
684 drmModeConnectorPtr c;
685 int ret;
686
687 ret = hwc_get_drm_display(ctx, display, &hd);
688 if (ret)
689 return ret;
690
691 if (hd->active_config < 0)
692 return -1;
693
694 c = drmModeGetConnector(ctx->fd, hd->connector_id);
695 if (!c) {
696 ALOGE("Failed to get connector %d", display);
697 return -ENODEV;
698 }
699
700 ret = hwc_check_config_valid(ctx, c, display, hd->active_config);
701 if (ret) {
702 ALOGE("Config is no longer valid %d", hd->active_config);
703 ret = -1;
704 goto out;
705 }
706
707 ret = hd->active_config;
708
709out:
710 drmModeFreeConnector(c);
711 return ret;
712}
713
714static bool hwc_crtc_is_bound(struct hwc_context_t *ctx, uint32_t crtc_id)
715{
716 int i;
717
718 for (i = 0; i < MAX_NUM_DISPLAYS; i++) {
719 if (ctx->displays[i].active_crtc == crtc_id)
720 return true;
721 }
722 return false;
723}
724
725static int hwc_try_encoder(struct hwc_context_t *ctx, drmModeResPtr r,
726 uint32_t encoder_id, uint32_t *crtc_id)
727{
728 drmModeEncoderPtr e;
729 int ret, i;
730
731 e = drmModeGetEncoder(ctx->fd, encoder_id);
732 if (!e) {
733 ALOGE("Failed to get encoder for connector %d", encoder_id);
734 return -ENODEV;
735 }
736
737 /* First try to use the currently-bound crtc */
738 if (e->crtc_id) {
739 if (!hwc_crtc_is_bound(ctx, e->crtc_id)) {
740 *crtc_id = e->crtc_id;
741 ret = 0;
742 goto out;
743 }
744 }
745
746 /* Try to find a possible crtc which will work */
747 for (i = 0; i < r->count_crtcs; i++) {
748 if (!(e->possible_crtcs & (1 << i)))
749 continue;
750
751 /* We've already tried this earlier */
752 if (e->crtc_id == r->crtcs[i])
753 continue;
754
755 if (!hwc_crtc_is_bound(ctx, r->crtcs[i])) {
756 *crtc_id = r->crtcs[i];
757 ret = 0;
758 goto out;
759 }
760 }
761
762 /* We can't use the encoder, but nothing went wrong, try another one */
763 ret = -EAGAIN;
764
765out:
766 drmModeFreeEncoder(e);
767 return ret;
768}
769
770static int hwc_set_active_config(struct hwc_composer_device_1* dev, int display,
771 int index)
772{
773 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
774 struct hwc_drm_display *hd = NULL;
775 drmModeResPtr r = NULL;
776 drmModeConnectorPtr c;
777 uint32_t crtc_id = 0;
778 int ret, i;
779 bool new_crtc, new_encoder;
780
781 ret = hwc_get_drm_display(ctx, display, &hd);
782 if (ret)
783 return ret;
784
785 c = drmModeGetConnector(ctx->fd, hd->connector_id);
786 if (!c) {
787 ALOGE("Failed to get connector %d", display);
788 return -ENODEV;
789 }
790
791 if (c->connection == DRM_MODE_DISCONNECTED) {
792 ALOGE("Tried to configure a disconnected display %d", display);
793 ret = -ENODEV;
794 goto out;
795 }
796
797 ret = hwc_check_config_valid(ctx, c, display, index);
798 if (ret) {
799 ALOGE("Provided config is no longer valid %u", index);
800 ret = -ENOENT;
801 goto out;
802 }
803
804 r = drmModeGetResources(ctx->fd);
805 if (!r) {
806 ALOGE("Failed to get drm resources");
807 goto out;
808 }
809
810 /* We no longer have an active_crtc */
811 hd->active_crtc = 0;
812
813 /* First, try to use the currently-connected encoder */
814 if (c->encoder_id) {
815 ret = hwc_try_encoder(ctx, r, c->encoder_id, &crtc_id);
816 if (ret && ret != -EAGAIN) {
817 ALOGE("Encoder try failed %d", ret);
818 goto out;
819 }
820 }
821
822 /* We couldn't find a crtc with the attached encoder, try the others */
823 if (!crtc_id) {
824 for (i = 0; i < c->count_encoders; i++) {
825 ret = hwc_try_encoder(ctx, r, c->encoders[i], &crtc_id);
826 if (!ret) {
827 break;
828 } else if (ret != -EAGAIN) {
829 ALOGE("Encoder try failed %d", ret);
830 goto out;
831 }
832 }
833 if (!crtc_id) {
834 ALOGE("Couldn't find valid crtc to modeset");
835 ret = -EINVAL;
836 goto out;
837 }
838 }
839
840 hd->active_crtc = crtc_id;
841 hd->active_config = index;
842
843 /* TODO: Once we have atomic, set the crtc timing info here */
844
845out:
846 if (r)
847 drmModeFreeResources(r);
848
849 drmModeFreeConnector(c);
850 return ret;
851}
852
Sean Paul9aa5ad32015-01-22 15:47:54 -0500853static int hwc_destroy_worker(struct hwc_worker *worker)
854{
855 int ret;
856
857 ret = pthread_mutex_lock(&worker->lock);
858 if (ret) {
859 ALOGE("Failed to lock in destroy() %d", ret);
860 return ret;
861 }
862
863 worker->exit = true;
864
865 ret |= pthread_cond_signal(&worker->cond);
866 if (ret)
867 ALOGE("Failed to signal cond in destroy() %d", ret);
868
869 ret |= pthread_mutex_unlock(&worker->lock);
870 if (ret)
871 ALOGE("Failed to unlock in destroy() %d", ret);
872
873 ret |= pthread_join(worker->thread, NULL);
874 if (ret && ret != ESRCH)
875 ALOGE("Failed to join thread in destroy() %d", ret);
876
877 return ret;
878}
879
880static void hwc_destroy_display(struct hwc_drm_display *hd)
881{
882 int ret;
883
884 if (hwc_destroy_worker(&hd->set_worker))
885 ALOGE("Destroy set worker failed");
886}
887
Sean Paule0c4c3d2015-01-20 16:56:04 -0500888static int hwc_device_close(struct hw_device_t *dev)
889{
890 struct hwc_context_t *ctx = (struct hwc_context_t *)dev;
Sean Paulcd36a9e2015-01-22 18:01:18 -0500891 int ret, i;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500892
Sean Paul9aa5ad32015-01-22 15:47:54 -0500893 for (i = 0; i < MAX_NUM_DISPLAYS; i++)
894 hwc_destroy_display(&ctx->displays[i]);
895
896 drmClose(ctx->fd);
Sean Paulcd36a9e2015-01-22 18:01:18 -0500897
898 ret = hwc_import_destroy(ctx->import_ctx);
899 if (ret)
900 ALOGE("Could not destroy import %d", ret);
901
Sean Paule0c4c3d2015-01-20 16:56:04 -0500902 free(ctx);
903
904 return 0;
905}
906
Sean Paul9aa5ad32015-01-22 15:47:54 -0500907static int hwc_initialize_worker(struct hwc_drm_display *hd,
908 struct hwc_worker *worker, void *(*routine)(void*))
909{
910 int ret;
911
912 ret = pthread_cond_init(&worker->cond, NULL);
913 if (ret) {
914 ALOGE("Failed to create worker condition %d", ret);
915 return ret;
916 }
917
918 ret = pthread_mutex_init(&worker->lock, NULL);
919 if (ret) {
920 ALOGE("Failed to initialize worker lock %d", ret);
921 goto err_cond;
922 }
923
924 worker->exit = false;
925
926 ret = pthread_create(&worker->thread, NULL, routine, hd);
927 if (ret) {
928 ALOGE("Could not create worker thread %d", ret);
929 goto err_lock;
930 }
931 return 0;
932
933err_lock:
934 pthread_mutex_destroy(&worker->lock);
935err_cond:
936 pthread_cond_destroy(&worker->cond);
937 return ret;
938}
939
Sean Paule0c4c3d2015-01-20 16:56:04 -0500940static int hwc_initialize_display(struct hwc_context_t *ctx, int display,
941 uint32_t connector_id)
942{
943 struct hwc_drm_display *hd = NULL;
944 int ret;
945
946 ret = hwc_get_drm_display(ctx, display, &hd);
947 if (ret)
948 return ret;
949
Sean Paul9aa5ad32015-01-22 15:47:54 -0500950 hd->ctx = ctx;
951 hd->display = display;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500952 hd->active_config = -1;
953 hd->connector_id = connector_id;
954
Sean Paul9aa5ad32015-01-22 15:47:54 -0500955 ret = hwc_initialize_worker(hd, &hd->set_worker, hwc_set_worker);
956 if (ret) {
957 ALOGE("Failed to create set worker %d\n", ret);
958 return ret;
959 }
960
Sean Paule0c4c3d2015-01-20 16:56:04 -0500961 return 0;
962}
963
964static int hwc_enumerate_displays(struct hwc_context_t *ctx)
965{
966 struct hwc_drm_display *panel_hd;
967 drmModeResPtr res;
968 drmModeConnectorPtr *conn_list;
969 int ret = 0, i, j;
970
971 res = drmModeGetResources(ctx->fd);
972 if (!res) {
973 ALOGE("Failed to get drm resources");
974 return -ENODEV;
975 }
976
977 conn_list = (drmModeConnector **)calloc(res->count_connectors,
978 sizeof(*conn_list));
979 if (!conn_list) {
980 ALOGE("Failed to allocate connector list");
981 ret = -ENOMEM;
982 goto out;
983 }
984
985 for (i = 0; i < res->count_connectors; i++) {
986 conn_list[i] = drmModeGetConnector(ctx->fd, res->connectors[i]);
987 if (!conn_list[i]) {
988 ALOGE("Failed to get connector %d", res->connectors[i]);
989 ret = -ENODEV;
990 goto out;
991 }
992 }
993
994 ctx->num_displays = 0;
995
996 /* Find a connected, panel type connector for display 0 */
997 for (i = 0; i < res->count_connectors; i++) {
998 drmModeConnectorPtr c = conn_list[i];
999
1000 for (j = 0; j < ARRAY_SIZE(panel_types); j++) {
1001 if (c->connector_type == panel_types[j] &&
1002 c->connection == DRM_MODE_CONNECTED)
1003 break;
1004 }
1005 if (j == ARRAY_SIZE(panel_types))
1006 continue;
1007
1008 hwc_initialize_display(ctx, ctx->num_displays, c->connector_id);
1009 ctx->num_displays++;
1010 break;
1011 }
1012
1013 ret = hwc_get_drm_display(ctx, 0, &panel_hd);
1014 if (ret)
1015 goto out;
1016
1017 /* Fill in the other displays */
1018 for (i = 0; i < res->count_connectors; i++) {
1019 drmModeConnectorPtr c = conn_list[i];
1020
1021 if (panel_hd->connector_id == c->connector_id)
1022 continue;
1023
1024 hwc_initialize_display(ctx, ctx->num_displays, c->connector_id);
1025 ctx->num_displays++;
1026 }
1027
1028out:
1029 for (i = 0; i < res->count_connectors; i++) {
1030 if (conn_list[i])
1031 drmModeFreeConnector(conn_list[i]);
1032 }
1033 free(conn_list);
1034
1035 if (res)
1036 drmModeFreeResources(res);
1037
1038 return ret;
1039}
1040
1041static int hwc_device_open(const struct hw_module_t* module, const char* name,
1042 struct hw_device_t** dev)
1043{
1044 int ret = 0;
1045 struct hwc_context_t *ctx;
1046
1047 if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
1048 ALOGE("Invalid module name- %s", name);
1049 return -EINVAL;
1050 }
1051
Sean Paul9b1bb842015-01-23 01:11:58 -05001052 ctx = new hwc_context_t();
Sean Paule0c4c3d2015-01-20 16:56:04 -05001053 if (!ctx) {
1054 ALOGE("Failed to allocate hwc context");
1055 return -ENOMEM;
1056 }
1057
Sean Paulcd36a9e2015-01-22 18:01:18 -05001058 ret = hwc_import_init(&ctx->import_ctx);
Sean Paule0c4c3d2015-01-20 16:56:04 -05001059 if (ret) {
Sean Paulcd36a9e2015-01-22 18:01:18 -05001060 ALOGE("Failed to initialize import context");
Sean Paule0c4c3d2015-01-20 16:56:04 -05001061 goto out;
1062 }
1063
1064 /* TODO: Use drmOpenControl here instead */
1065 ctx->fd = open(HWCOMPOSER_DRM_DEVICE, O_RDWR);
1066 if (ctx->fd < 0) {
1067 ALOGE("Failed to open dri- %s", strerror(-errno));
1068 goto out;
1069 }
1070
1071 ret = drmSetMaster(ctx->fd);
1072 if (ret) {
1073 ALOGE("Failed to set hwcomposer as drm master %d", ret);
1074 goto out;
1075 }
1076
1077 ret = hwc_enumerate_displays(ctx);
1078 if (ret) {
1079 ALOGE("Failed to enumerate displays: %s", strerror(ret));
1080 goto out;
1081 }
1082
1083 ctx->device.common.tag = HARDWARE_DEVICE_TAG;
1084 ctx->device.common.version = HWC_DEVICE_API_VERSION_1_4;
1085 ctx->device.common.module = const_cast<hw_module_t*>(module);
1086 ctx->device.common.close = hwc_device_close;
1087
1088 ctx->device.prepare = hwc_prepare;
1089 ctx->device.set = hwc_set;
1090 ctx->device.eventControl = hwc_event_control;
1091 ctx->device.setPowerMode = hwc_set_power_mode;
1092 ctx->device.query = hwc_query;
1093 ctx->device.registerProcs = hwc_register_procs;
1094 ctx->device.getDisplayConfigs = hwc_get_display_configs;
1095 ctx->device.getDisplayAttributes = hwc_get_display_attributes;
1096 ctx->device.getActiveConfig = hwc_get_active_config;
1097 ctx->device.setActiveConfig = hwc_set_active_config;
1098 ctx->device.setCursorPositionAsync = NULL; /* TODO: Add cursor */
1099
1100 *dev = &ctx->device.common;
1101
1102 return 0;
1103out:
1104 if (ctx->fd >= 0)
1105 close(ctx->fd);
1106
1107 free(ctx);
1108 return ret;
1109}
1110
1111static struct hw_module_methods_t hwc_module_methods = {
1112 open: hwc_device_open
1113};
1114
1115hwc_module_t HAL_MODULE_INFO_SYM = {
1116 common: {
1117 tag: HARDWARE_MODULE_TAG,
1118 version_major: 1,
1119 version_minor: 0,
1120 id: HWC_HARDWARE_MODULE_ID,
1121 name: "DRM hwcomposer module",
1122 author: "The Android Open Source Project",
1123 methods: &hwc_module_methods,
1124 dso: NULL,
1125 reserved: { 0 },
1126 }
1127};