blob: 175e5735cd3c03ed03fe5c497d0d229a4a0ded81 [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 Paule0c4c3d2015-01-20 16:56:04 -050024
25#include <cutils/log.h>
26
27#include <xf86drm.h>
28#include <xf86drmMode.h>
29#include <drm/drm_fourcc.h>
30
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 Paule0c4c3d2015-01-20 16:56:04 -050036#include <gralloc_drm.h>
37#include <gralloc_drm_priv.h>
38#include <gralloc_drm_handle.h>
39
40#define ARRAY_SIZE(arr) (int)(sizeof(arr) / sizeof((arr)[0]))
41
42#define HWCOMPOSER_DRM_DEVICE "/dev/dri/card0"
43#define MAX_NUM_DISPLAYS 3
44#define UM_PER_INCH 25400
45
46static const uint32_t panel_types[] = {
47 DRM_MODE_CONNECTOR_LVDS,
48 DRM_MODE_CONNECTOR_eDP,
49 DRM_MODE_CONNECTOR_DSI,
50};
51
Sean Paul9aa5ad32015-01-22 15:47:54 -050052struct hwc_drm_bo {
53 int fd; /* TODO: This is bad voodoo, remove it */
54 uint32_t width;
55 uint32_t height;
56 uint32_t format;
57 uint32_t pitches[4];
58 uint32_t offsets[4];
59 uint32_t gem_handles[4];
60 uint32_t fb_id;
61 int acquire_fence_fd;
62};
63
64struct hwc_worker {
65 pthread_t thread;
66 pthread_mutex_t lock;
67 pthread_cond_t cond;
68 bool exit;
69};
70
Sean Paule0c4c3d2015-01-20 16:56:04 -050071struct hwc_drm_display {
Sean Paul9aa5ad32015-01-22 15:47:54 -050072 struct hwc_context_t *ctx;
73 int display;
74
Sean Paule0c4c3d2015-01-20 16:56:04 -050075 uint32_t connector_id;
76
77 drmModeModeInfoPtr configs;
78 uint32_t num_configs;
79
80 int active_config;
81 uint32_t active_crtc;
Sean Paul9aa5ad32015-01-22 15:47:54 -050082
83 struct hwc_worker set_worker;
84
85 struct hwc_drm_bo front;
86 struct hwc_drm_bo back;
Sean Paule0c4c3d2015-01-20 16:56:04 -050087};
88
89struct hwc_context_t {
90 hwc_composer_device_1_t device;
91
92 int fd;
93 struct drm_module_t *gralloc_module; /* TODO: NUKE THIS */
94
95 hwc_procs_t const *procs;
96
97 struct hwc_drm_display displays[MAX_NUM_DISPLAYS];
98 int num_displays;
99};
100
101static int hwc_get_drm_display(struct hwc_context_t *ctx, int display,
102 struct hwc_drm_display **hd)
103{
104 if (display >= MAX_NUM_DISPLAYS) {
105 ALOGE("Requested display is out-of-bounds %d %d", display,
106 MAX_NUM_DISPLAYS);
107 return -EINVAL;
108 }
109 *hd = &ctx->displays[display];
110 return 0;
111}
112
113static int hwc_prepare_layer(hwc_layer_1_t *layer)
114{
115 /* TODO: We can't handle background right now, defer to sufaceFlinger */
116 if (layer->compositionType == HWC_BACKGROUND) {
117 layer->compositionType = HWC_FRAMEBUFFER;
118 ALOGV("Can't handle background layers yet");
119
120 /* TODO: Support sideband compositions */
121 } else if (layer->compositionType == HWC_SIDEBAND) {
122 layer->compositionType = HWC_FRAMEBUFFER;
123 ALOGV("Can't handle sideband content yet");
124 }
125
126 layer->hints = 0;
127
128 /* TODO: Handle cursor by setting compositionType=HWC_CURSOR_OVERLAY */
129 if (layer->flags & HWC_IS_CURSOR_LAYER) {
130 ALOGV("Can't handle async cursors yet");
131 }
132
133 /* TODO: Handle transformations */
134 if (layer->transform) {
135 ALOGV("Can't handle transformations yet");
136 }
137
138 /* TODO: Handle blending & plane alpha*/
139 if (layer->blending == HWC_BLENDING_PREMULT ||
140 layer->blending == HWC_BLENDING_COVERAGE) {
141 ALOGV("Can't handle blending yet");
142 }
143
144 /* TODO: Handle cropping & scaling */
145
146 return 0;
147}
148
149static int hwc_prepare(hwc_composer_device_1_t */* dev */, size_t num_displays,
150 hwc_display_contents_1_t** display_contents)
151{
152 int ret = 0, i, j;
153
154 /* TODO: Check flags for HWC_GEOMETRY_CHANGED */
155
156 for (i = 0; i < (int)num_displays && i < MAX_NUM_DISPLAYS; i++) {
157 for (j = 0; j < (int)display_contents[i]->numHwLayers; j++) {
158 ret = hwc_prepare_layer(
159 &display_contents[i]->hwLayers[j]);
160 if (ret) {
161 ALOGE("Failed to prepare layer %d:%d", j, i);
162 return ret;
163 }
164 }
165 }
166
167 return ret;
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
220static int hwc_flip(struct hwc_drm_display *hd)
221{
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) {
233 ret = drmModeSetCrtc(hd->ctx->fd, hd->active_crtc,
234 hd->back.fb_id, 0, 0, &hd->connector_id, 1,
235 &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
250 ret = drmModePageFlip(hd->ctx->fd, hd->active_crtc, hd->back.fb_id,
251 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;
274
275 ret = drmModeAddFB2(hd->back.fd, hd->back.width, hd->back.height,
276 hd->back.format, hd->back.gem_handles, hd->back.pitches,
277 hd->back.offsets, &hd->back.fb_id, 0);
278 if (ret) {
279 ALOGE("could not create drm fb %d", ret);
280 return ret;
281 }
282
283 if (hd->back.acquire_fence_fd >= 0) {
284 ret = sync_wait(hd->back.acquire_fence_fd, -1);
285 if (ret) {
286 ALOGE("Failed to wait for acquire %d", ret);
287 return ret;
288 }
289 }
290
291 ret = hwc_flip(hd);
292 if (ret) {
293 ALOGE("Failed to perform flip\n");
294 return ret;
295 }
296
297 if (hd->front.fb_id) {
298 ret = drmModeRmFB(hd->front.fd, hd->front.fb_id);
299 if (ret) {
300 ALOGE("Failed to rm fb from front %d", ret);
301 return ret;
302 }
303 }
304 hd->front = hd->back;
305
306 memset(&hd->back, 0, sizeof(hd->back));
307 hd->back.acquire_fence_fd = -1;
308
309 return ret;
310}
311
312static void *hwc_set_worker(void *arg)
313{
314 struct hwc_drm_display *hd = (struct hwc_drm_display *)arg;
315 int ret;
316
317 setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
318
319 ret = pthread_mutex_lock(&hd->set_worker.lock);
320 if (ret) {
321 ALOGE("Failed to lock set lock %d", ret);
322 return NULL;
323 }
324
325 do {
326 ret = pthread_cond_wait(&hd->set_worker.cond,
327 &hd->set_worker.lock);
328 if (ret) {
329 ALOGE("Failed to wait on set condition %d", ret);
330 break;
331 } else if (hd->set_worker.exit) {
332 break;
333 }
334
335 ret = hwc_wait_and_set(hd);
336 if (ret)
337 ALOGE("Failed to wait and set %d", ret);
338 } while (true);
339
340 ret = pthread_mutex_unlock(&hd->set_worker.lock);
341 if (ret) {
342 ALOGE("Failed to unlock set lock %d", ret);
343 return NULL;
344 }
345
346 return NULL;
347}
348
349static uint32_t hwc_convert_hal_format_to_drm_format(uint32_t hal_format)
350{
351 switch(hal_format) {
352 case HAL_PIXEL_FORMAT_RGB_888:
353 return DRM_FORMAT_BGR888;
354 case HAL_PIXEL_FORMAT_BGRA_8888:
355 return DRM_FORMAT_ARGB8888;
356 case HAL_PIXEL_FORMAT_RGBX_8888:
357 return DRM_FORMAT_XBGR8888;
358 case HAL_PIXEL_FORMAT_RGBA_8888:
359 return DRM_FORMAT_ABGR8888;
360 case HAL_PIXEL_FORMAT_RGB_565:
361 return DRM_FORMAT_BGR565;
362 case HAL_PIXEL_FORMAT_YV12:
363 return DRM_FORMAT_YVU420;
364 default:
365 ALOGE("Cannot convert hal format to drm format %u", hal_format);
366 return -EINVAL;
367 }
368}
369
370/* TODO: NUKE THIS */
371static int hwc_convert_gralloc_handle_to_drm_bo(hwc_context_t *ctx,
372 buffer_handle_t handle, struct hwc_drm_bo *bo)
373{
374 gralloc_drm_t *drm = ctx->gralloc_module->drm;
375 gralloc_drm_handle_t *gr_handle;
376 struct gralloc_drm_bo_t *gralloc_bo;
377
378 gr_handle = (gralloc_drm_handle_t *)handle;
379
380 gralloc_bo = gr_handle->data;
381 if (!gralloc_bo) {
382 ALOGE("Could not get drm bo from handle");
383 return -EINVAL;
384 }
385
386 bo->fd = drm->fd;
387 bo->width = gr_handle->width;
388 bo->height = gr_handle->height;
389 bo->format = hwc_convert_hal_format_to_drm_format(gr_handle->format);
390 bo->pitches[0] = gr_handle->stride;
391 bo->gem_handles[0] = gralloc_bo->fb_handle;
392
393 return 0;
394}
395
Sean Paule0c4c3d2015-01-20 16:56:04 -0500396static int hwc_set_display(hwc_context_t *ctx, int display,
397 hwc_display_contents_1_t* display_contents)
398{
399 struct hwc_drm_display *hd = NULL;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500400 hwc_layer_1_t *layer = NULL;
401 int ret, i;
Sean Paul9aa5ad32015-01-22 15:47:54 -0500402 uint32_t fb_id;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500403
404 ret = hwc_get_drm_display(ctx, display, &hd);
405 if (ret)
406 return ret;
407
408 if (!hd->active_crtc) {
409 ALOGE("There is no active crtc for display %d", display);
410 return -ENOENT;
411 }
412
413 /*
414 * TODO: We can only support one hw layer atm, so choose either the
415 * first one or the framebuffer target.
416 */
417 if (!display_contents->numHwLayers) {
418 return 0;
419 } else if (display_contents->numHwLayers == 1) {
420 layer = &display_contents->hwLayers[0];
421 } else {
422 for (i = 0; i < (int)display_contents->numHwLayers; i++) {
423 layer = &display_contents->hwLayers[i];
424 if (layer->compositionType == HWC_FRAMEBUFFER_TARGET)
425 break;
426 }
427 if (i == (int)display_contents->numHwLayers) {
428 ALOGE("Could not find a suitable layer for display %d",
429 display);
430 }
431 }
432
Sean Paul9aa5ad32015-01-22 15:47:54 -0500433 ret = pthread_mutex_lock(&hd->set_worker.lock);
Sean Paule0c4c3d2015-01-20 16:56:04 -0500434 if (ret) {
Sean Paul9aa5ad32015-01-22 15:47:54 -0500435 ALOGE("Failed to lock set lock in set() %d", ret);
436 return ret;
437 }
438
439 if (hd->back.gem_handles[0]) {
440 ALOGE("Failing set, back buffer already exists");
441 ret = -EINVAL;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500442 goto out;
443 }
444
Sean Paul9aa5ad32015-01-22 15:47:54 -0500445 ret = hwc_convert_gralloc_handle_to_drm_bo(ctx, layer->handle,
446 &hd->back);
447 if (ret) {
448 ALOGE("Failed to convert gralloc handle to drm bo %d", ret);
449 goto out;
450 }
451
452 hd->back.acquire_fence_fd = layer->acquireFenceFd;
453 layer->releaseFenceFd = -1;
454
455 ret = pthread_cond_signal(&hd->set_worker.cond);
456 if (ret) {
457 ALOGE("Failed to signal set worker %d", ret);
458 goto out;
459 }
460
461 ret = pthread_mutex_unlock(&hd->set_worker.lock);
462 if (ret) {
463 ALOGE("Failed to unlock set lock in set() %d", ret);
464 return ret;
465 }
466
467 return ret;
468
Sean Paule0c4c3d2015-01-20 16:56:04 -0500469out:
Sean Paul9aa5ad32015-01-22 15:47:54 -0500470 if (pthread_mutex_unlock(&hd->set_worker.lock))
471 ALOGE("Failed to unlock set lock in set error handler");
472
Sean Paule0c4c3d2015-01-20 16:56:04 -0500473 return ret;
474}
475
476static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays,
477 hwc_display_contents_1_t** display_contents)
478{
479 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
480 int ret = 0, i;
481
482 /* TODO: Handle acquire & release fences */
483
484 for (i = 0; i < (int)num_displays && i < MAX_NUM_DISPLAYS; i++) {
485 display_contents[i]->retireFenceFd = -1; /* TODO: sync */
486
487 ret = hwc_set_display(ctx, i, display_contents[i]);
488 }
489
490 return ret;
491}
492
493static int hwc_event_control(struct hwc_composer_device_1 */* dev */,
494 int /* display */, int /* event */, int /* enabled */)
495{
496 int ret;
497
498 /* TODO */
499 return 0;
500}
501
502static int hwc_set_power_mode(struct hwc_composer_device_1* dev, int display,
503 int mode)
504{
505 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
506 struct hwc_drm_display *hd = NULL;
507 drmModeConnectorPtr c;
508 int ret, i;
509 uint32_t dpms_prop = 0;
510 uint64_t dpms_value = 0;
511
512 ret = hwc_get_drm_display(ctx, display, &hd);
513 if (ret)
514 return ret;
515
516 c = drmModeGetConnector(ctx->fd, hd->connector_id);
517 if (!c) {
518 ALOGE("Failed to get connector %d", display);
519 return -ENODEV;
520 }
521
522 for (i = 0; !dpms_prop && i < c->count_props; i++) {
523 drmModePropertyPtr p;
524
525 p = drmModeGetProperty(ctx->fd, c->props[i]);
526 if (!p)
527 continue;
528
529 if (!strcmp(p->name, "DPMS"))
530 dpms_prop = c->props[i];
531
532 drmModeFreeProperty(p);
533 }
534 if (!dpms_prop) {
535 ALOGE("Failed to get DPMS property from display %d", display);
536 ret = -ENOENT;
537 goto out;
538 }
539
540 switch(mode) {
541 case HWC_POWER_MODE_OFF:
542 dpms_value = DRM_MODE_DPMS_OFF;
543 break;
544
545 /* We can't support dozing right now, so go full on */
546 case HWC_POWER_MODE_DOZE:
547 case HWC_POWER_MODE_DOZE_SUSPEND:
548 case HWC_POWER_MODE_NORMAL:
549 dpms_value = DRM_MODE_DPMS_ON;
550 break;
551 };
552
553 ret = drmModeConnectorSetProperty(ctx->fd, c->connector_id,
554 dpms_prop, dpms_value);
555 if (ret) {
556 ALOGE("Failed to set DPMS property for display %d", display);
557 goto out;
558 }
559
560out:
561 drmModeFreeConnector(c);
562 return ret;
563}
564
565static int hwc_query(struct hwc_composer_device_1 */* dev */, int what,
566 int *value)
567{
568 switch(what) {
569 case HWC_BACKGROUND_LAYER_SUPPORTED:
570 *value = 0; /* TODO: We should do this */
571 break;
572 case HWC_VSYNC_PERIOD:
573 ALOGW("Query for deprecated vsync value, returning 60Hz");
574 *value = 1000 * 1000 * 1000 / 60;
575 break;
576 case HWC_DISPLAY_TYPES_SUPPORTED:
577 *value = HWC_DISPLAY_PRIMARY | HWC_DISPLAY_EXTERNAL;
578 break;
579 }
580 return 0;
581}
582
583static void hwc_register_procs(struct hwc_composer_device_1* dev,
584 hwc_procs_t const* procs)
585{
586 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
587
588 ctx->procs = procs;
589}
590
591static int hwc_get_display_configs(struct hwc_composer_device_1* dev,
592 int display, uint32_t* configs, size_t* numConfigs)
593{
594 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
595 struct hwc_drm_display *hd = NULL;
596 drmModeConnectorPtr c;
597 int ret = 0, i;
598
599 if (!*numConfigs)
600 return 0;
601
602 ret = hwc_get_drm_display(ctx, display, &hd);
603 if (ret)
604 return ret;
605
606 c = drmModeGetConnector(ctx->fd, hd->connector_id);
607 if (!c) {
608 ALOGE("Failed to get connector %d", display);
609 return -ENODEV;
610 }
611
612 if (hd->configs)
613 free(hd->configs);
614
615 hd->active_config = -1;
616 hd->configs = (drmModeModeInfoPtr)calloc(c->count_modes,
617 sizeof(*hd->configs));
618 if (!hd->configs) {
619 ALOGE("Failed to allocate config list for display %d", display);
620 ret = -ENOMEM;
621 hd->num_configs = 0;
622 goto out;
623 }
624
625 for (i = 0; i < c->count_modes; i++) {
626 drmModeModeInfoPtr m = &hd->configs[i];
627
628 memcpy(m, &c->modes[i], sizeof(*m));
629
630 if (i < (int)*numConfigs)
631 configs[i] = i;
632 }
633
634 hd->num_configs = c->count_modes;
635 *numConfigs = MIN(c->count_modes, *numConfigs);
636
637out:
638 drmModeFreeConnector(c);
639 return ret;
640}
641
642static int hwc_check_config_valid(struct hwc_context_t *ctx,
643 drmModeConnectorPtr connector, int display,
644 int config_idx)
645{
646 struct hwc_drm_display *hd = NULL;
647 drmModeModeInfoPtr m = NULL;
648 int ret = 0, i;
649
650 ret = hwc_get_drm_display(ctx, display, &hd);
651 if (ret)
652 return ret;
653
654 /* Make sure the requested config is still valid for the display */
655 for (i = 0; i < connector->count_modes; i++) {
656 if (hwc_mode_is_equal(&connector->modes[i],
657 &hd->configs[config_idx])) {
658 m = &hd->configs[config_idx];
659 break;
660 }
661 }
662 if (!m)
663 return -ENOENT;
664
665 return 0;
666}
667
668static int hwc_get_display_attributes(struct hwc_composer_device_1* dev,
669 int display, uint32_t config, const uint32_t* attributes,
670 int32_t* values)
671{
672 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
673 struct hwc_drm_display *hd = NULL;
674 drmModeConnectorPtr c;
675 drmModeModeInfoPtr m;
676 int ret, i;
677
678 ret = hwc_get_drm_display(ctx, display, &hd);
679 if (ret)
680 return ret;
681
682 if (config >= hd->num_configs) {
683 ALOGE("Requested config is out-of-bounds %d %d", config,
684 hd->num_configs);
685 return -EINVAL;
686 }
687
688 c = drmModeGetConnector(ctx->fd, hd->connector_id);
689 if (!c) {
690 ALOGE("Failed to get connector %d", display);
691 return -ENODEV;
692 }
693
694 ret = hwc_check_config_valid(ctx, c, display, (int)config);
695 if (ret) {
696 ALOGE("Provided config is no longer valid %u", config);
697 goto out;
698 }
699
700 m = &hd->configs[config];
701 for (i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) {
702 switch(attributes[i]) {
703 case HWC_DISPLAY_VSYNC_PERIOD:
704 values[i] = 1000 * 1000 * 1000 / m->vrefresh;
705 break;
706 case HWC_DISPLAY_WIDTH:
707 values[i] = m->hdisplay;
708 break;
709 case HWC_DISPLAY_HEIGHT:
710 values[i] = m->vdisplay;
711 break;
712 case HWC_DISPLAY_DPI_X:
713 /* Dots per 1000 inches */
714 values[i] = c->mmWidth ?
715 (m->hdisplay * UM_PER_INCH) / c->mmWidth : 0;
716 break;
717 case HWC_DISPLAY_DPI_Y:
718 /* Dots per 1000 inches */
719 values[i] = c->mmHeight ?
720 (m->vdisplay * UM_PER_INCH) / c->mmHeight : 0;
721 break;
722 }
723 }
724
725out:
726 drmModeFreeConnector(c);
727 return ret;
728}
729
730static int hwc_get_active_config(struct hwc_composer_device_1* dev, int display)
731{
732 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
733 struct hwc_drm_display *hd = NULL;
734 drmModeConnectorPtr c;
735 int ret;
736
737 ret = hwc_get_drm_display(ctx, display, &hd);
738 if (ret)
739 return ret;
740
741 if (hd->active_config < 0)
742 return -1;
743
744 c = drmModeGetConnector(ctx->fd, hd->connector_id);
745 if (!c) {
746 ALOGE("Failed to get connector %d", display);
747 return -ENODEV;
748 }
749
750 ret = hwc_check_config_valid(ctx, c, display, hd->active_config);
751 if (ret) {
752 ALOGE("Config is no longer valid %d", hd->active_config);
753 ret = -1;
754 goto out;
755 }
756
757 ret = hd->active_config;
758
759out:
760 drmModeFreeConnector(c);
761 return ret;
762}
763
764static bool hwc_crtc_is_bound(struct hwc_context_t *ctx, uint32_t crtc_id)
765{
766 int i;
767
768 for (i = 0; i < MAX_NUM_DISPLAYS; i++) {
769 if (ctx->displays[i].active_crtc == crtc_id)
770 return true;
771 }
772 return false;
773}
774
775static int hwc_try_encoder(struct hwc_context_t *ctx, drmModeResPtr r,
776 uint32_t encoder_id, uint32_t *crtc_id)
777{
778 drmModeEncoderPtr e;
779 int ret, i;
780
781 e = drmModeGetEncoder(ctx->fd, encoder_id);
782 if (!e) {
783 ALOGE("Failed to get encoder for connector %d", encoder_id);
784 return -ENODEV;
785 }
786
787 /* First try to use the currently-bound crtc */
788 if (e->crtc_id) {
789 if (!hwc_crtc_is_bound(ctx, e->crtc_id)) {
790 *crtc_id = e->crtc_id;
791 ret = 0;
792 goto out;
793 }
794 }
795
796 /* Try to find a possible crtc which will work */
797 for (i = 0; i < r->count_crtcs; i++) {
798 if (!(e->possible_crtcs & (1 << i)))
799 continue;
800
801 /* We've already tried this earlier */
802 if (e->crtc_id == r->crtcs[i])
803 continue;
804
805 if (!hwc_crtc_is_bound(ctx, r->crtcs[i])) {
806 *crtc_id = r->crtcs[i];
807 ret = 0;
808 goto out;
809 }
810 }
811
812 /* We can't use the encoder, but nothing went wrong, try another one */
813 ret = -EAGAIN;
814
815out:
816 drmModeFreeEncoder(e);
817 return ret;
818}
819
820static int hwc_set_active_config(struct hwc_composer_device_1* dev, int display,
821 int index)
822{
823 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
824 struct hwc_drm_display *hd = NULL;
825 drmModeResPtr r = NULL;
826 drmModeConnectorPtr c;
827 uint32_t crtc_id = 0;
828 int ret, i;
829 bool new_crtc, new_encoder;
830
831 ret = hwc_get_drm_display(ctx, display, &hd);
832 if (ret)
833 return ret;
834
835 c = drmModeGetConnector(ctx->fd, hd->connector_id);
836 if (!c) {
837 ALOGE("Failed to get connector %d", display);
838 return -ENODEV;
839 }
840
841 if (c->connection == DRM_MODE_DISCONNECTED) {
842 ALOGE("Tried to configure a disconnected display %d", display);
843 ret = -ENODEV;
844 goto out;
845 }
846
847 ret = hwc_check_config_valid(ctx, c, display, index);
848 if (ret) {
849 ALOGE("Provided config is no longer valid %u", index);
850 ret = -ENOENT;
851 goto out;
852 }
853
854 r = drmModeGetResources(ctx->fd);
855 if (!r) {
856 ALOGE("Failed to get drm resources");
857 goto out;
858 }
859
860 /* We no longer have an active_crtc */
861 hd->active_crtc = 0;
862
863 /* First, try to use the currently-connected encoder */
864 if (c->encoder_id) {
865 ret = hwc_try_encoder(ctx, r, c->encoder_id, &crtc_id);
866 if (ret && ret != -EAGAIN) {
867 ALOGE("Encoder try failed %d", ret);
868 goto out;
869 }
870 }
871
872 /* We couldn't find a crtc with the attached encoder, try the others */
873 if (!crtc_id) {
874 for (i = 0; i < c->count_encoders; i++) {
875 ret = hwc_try_encoder(ctx, r, c->encoders[i], &crtc_id);
876 if (!ret) {
877 break;
878 } else if (ret != -EAGAIN) {
879 ALOGE("Encoder try failed %d", ret);
880 goto out;
881 }
882 }
883 if (!crtc_id) {
884 ALOGE("Couldn't find valid crtc to modeset");
885 ret = -EINVAL;
886 goto out;
887 }
888 }
889
890 hd->active_crtc = crtc_id;
891 hd->active_config = index;
892
893 /* TODO: Once we have atomic, set the crtc timing info here */
894
895out:
896 if (r)
897 drmModeFreeResources(r);
898
899 drmModeFreeConnector(c);
900 return ret;
901}
902
Sean Paul9aa5ad32015-01-22 15:47:54 -0500903static int hwc_destroy_worker(struct hwc_worker *worker)
904{
905 int ret;
906
907 ret = pthread_mutex_lock(&worker->lock);
908 if (ret) {
909 ALOGE("Failed to lock in destroy() %d", ret);
910 return ret;
911 }
912
913 worker->exit = true;
914
915 ret |= pthread_cond_signal(&worker->cond);
916 if (ret)
917 ALOGE("Failed to signal cond in destroy() %d", ret);
918
919 ret |= pthread_mutex_unlock(&worker->lock);
920 if (ret)
921 ALOGE("Failed to unlock in destroy() %d", ret);
922
923 ret |= pthread_join(worker->thread, NULL);
924 if (ret && ret != ESRCH)
925 ALOGE("Failed to join thread in destroy() %d", ret);
926
927 return ret;
928}
929
930static void hwc_destroy_display(struct hwc_drm_display *hd)
931{
932 int ret;
933
934 if (hwc_destroy_worker(&hd->set_worker))
935 ALOGE("Destroy set worker failed");
936}
937
Sean Paule0c4c3d2015-01-20 16:56:04 -0500938static int hwc_device_close(struct hw_device_t *dev)
939{
940 struct hwc_context_t *ctx = (struct hwc_context_t *)dev;
Sean Paul9aa5ad32015-01-22 15:47:54 -0500941 int i;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500942
Sean Paul9aa5ad32015-01-22 15:47:54 -0500943 for (i = 0; i < MAX_NUM_DISPLAYS; i++)
944 hwc_destroy_display(&ctx->displays[i]);
945
946 drmClose(ctx->fd);
Sean Paule0c4c3d2015-01-20 16:56:04 -0500947 free(ctx);
948
949 return 0;
950}
951
Sean Paul9aa5ad32015-01-22 15:47:54 -0500952static int hwc_initialize_worker(struct hwc_drm_display *hd,
953 struct hwc_worker *worker, void *(*routine)(void*))
954{
955 int ret;
956
957 ret = pthread_cond_init(&worker->cond, NULL);
958 if (ret) {
959 ALOGE("Failed to create worker condition %d", ret);
960 return ret;
961 }
962
963 ret = pthread_mutex_init(&worker->lock, NULL);
964 if (ret) {
965 ALOGE("Failed to initialize worker lock %d", ret);
966 goto err_cond;
967 }
968
969 worker->exit = false;
970
971 ret = pthread_create(&worker->thread, NULL, routine, hd);
972 if (ret) {
973 ALOGE("Could not create worker thread %d", ret);
974 goto err_lock;
975 }
976 return 0;
977
978err_lock:
979 pthread_mutex_destroy(&worker->lock);
980err_cond:
981 pthread_cond_destroy(&worker->cond);
982 return ret;
983}
984
Sean Paule0c4c3d2015-01-20 16:56:04 -0500985static int hwc_initialize_display(struct hwc_context_t *ctx, int display,
986 uint32_t connector_id)
987{
988 struct hwc_drm_display *hd = NULL;
989 int ret;
990
991 ret = hwc_get_drm_display(ctx, display, &hd);
992 if (ret)
993 return ret;
994
Sean Paul9aa5ad32015-01-22 15:47:54 -0500995 hd->ctx = ctx;
996 hd->display = display;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500997 hd->active_config = -1;
998 hd->connector_id = connector_id;
999
Sean Paul9aa5ad32015-01-22 15:47:54 -05001000 ret = hwc_initialize_worker(hd, &hd->set_worker, hwc_set_worker);
1001 if (ret) {
1002 ALOGE("Failed to create set worker %d\n", ret);
1003 return ret;
1004 }
1005
Sean Paule0c4c3d2015-01-20 16:56:04 -05001006 return 0;
1007}
1008
1009static int hwc_enumerate_displays(struct hwc_context_t *ctx)
1010{
1011 struct hwc_drm_display *panel_hd;
1012 drmModeResPtr res;
1013 drmModeConnectorPtr *conn_list;
1014 int ret = 0, i, j;
1015
1016 res = drmModeGetResources(ctx->fd);
1017 if (!res) {
1018 ALOGE("Failed to get drm resources");
1019 return -ENODEV;
1020 }
1021
1022 conn_list = (drmModeConnector **)calloc(res->count_connectors,
1023 sizeof(*conn_list));
1024 if (!conn_list) {
1025 ALOGE("Failed to allocate connector list");
1026 ret = -ENOMEM;
1027 goto out;
1028 }
1029
1030 for (i = 0; i < res->count_connectors; i++) {
1031 conn_list[i] = drmModeGetConnector(ctx->fd, res->connectors[i]);
1032 if (!conn_list[i]) {
1033 ALOGE("Failed to get connector %d", res->connectors[i]);
1034 ret = -ENODEV;
1035 goto out;
1036 }
1037 }
1038
1039 ctx->num_displays = 0;
1040
1041 /* Find a connected, panel type connector for display 0 */
1042 for (i = 0; i < res->count_connectors; i++) {
1043 drmModeConnectorPtr c = conn_list[i];
1044
1045 for (j = 0; j < ARRAY_SIZE(panel_types); j++) {
1046 if (c->connector_type == panel_types[j] &&
1047 c->connection == DRM_MODE_CONNECTED)
1048 break;
1049 }
1050 if (j == ARRAY_SIZE(panel_types))
1051 continue;
1052
1053 hwc_initialize_display(ctx, ctx->num_displays, c->connector_id);
1054 ctx->num_displays++;
1055 break;
1056 }
1057
1058 ret = hwc_get_drm_display(ctx, 0, &panel_hd);
1059 if (ret)
1060 goto out;
1061
1062 /* Fill in the other displays */
1063 for (i = 0; i < res->count_connectors; i++) {
1064 drmModeConnectorPtr c = conn_list[i];
1065
1066 if (panel_hd->connector_id == c->connector_id)
1067 continue;
1068
1069 hwc_initialize_display(ctx, ctx->num_displays, c->connector_id);
1070 ctx->num_displays++;
1071 }
1072
1073out:
1074 for (i = 0; i < res->count_connectors; i++) {
1075 if (conn_list[i])
1076 drmModeFreeConnector(conn_list[i]);
1077 }
1078 free(conn_list);
1079
1080 if (res)
1081 drmModeFreeResources(res);
1082
1083 return ret;
1084}
1085
1086static int hwc_device_open(const struct hw_module_t* module, const char* name,
1087 struct hw_device_t** dev)
1088{
1089 int ret = 0;
1090 struct hwc_context_t *ctx;
1091
1092 if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
1093 ALOGE("Invalid module name- %s", name);
1094 return -EINVAL;
1095 }
1096
1097 ctx = (hwc_context_t *)calloc(1, sizeof(*ctx));
1098 if (!ctx) {
1099 ALOGE("Failed to allocate hwc context");
1100 return -ENOMEM;
1101 }
1102
1103 /* TODO: NUKE THIS */
1104 ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
1105 (const hw_module_t **)&ctx->gralloc_module);
1106 if (ret) {
1107 ALOGE("Failed to open gralloc module");
1108 goto out;
1109 }
1110
1111 /* TODO: Use drmOpenControl here instead */
1112 ctx->fd = open(HWCOMPOSER_DRM_DEVICE, O_RDWR);
1113 if (ctx->fd < 0) {
1114 ALOGE("Failed to open dri- %s", strerror(-errno));
1115 goto out;
1116 }
1117
1118 ret = drmSetMaster(ctx->fd);
1119 if (ret) {
1120 ALOGE("Failed to set hwcomposer as drm master %d", ret);
1121 goto out;
1122 }
1123
1124 ret = hwc_enumerate_displays(ctx);
1125 if (ret) {
1126 ALOGE("Failed to enumerate displays: %s", strerror(ret));
1127 goto out;
1128 }
1129
1130 ctx->device.common.tag = HARDWARE_DEVICE_TAG;
1131 ctx->device.common.version = HWC_DEVICE_API_VERSION_1_4;
1132 ctx->device.common.module = const_cast<hw_module_t*>(module);
1133 ctx->device.common.close = hwc_device_close;
1134
1135 ctx->device.prepare = hwc_prepare;
1136 ctx->device.set = hwc_set;
1137 ctx->device.eventControl = hwc_event_control;
1138 ctx->device.setPowerMode = hwc_set_power_mode;
1139 ctx->device.query = hwc_query;
1140 ctx->device.registerProcs = hwc_register_procs;
1141 ctx->device.getDisplayConfigs = hwc_get_display_configs;
1142 ctx->device.getDisplayAttributes = hwc_get_display_attributes;
1143 ctx->device.getActiveConfig = hwc_get_active_config;
1144 ctx->device.setActiveConfig = hwc_set_active_config;
1145 ctx->device.setCursorPositionAsync = NULL; /* TODO: Add cursor */
1146
1147 *dev = &ctx->device.common;
1148
1149 return 0;
1150out:
1151 if (ctx->fd >= 0)
1152 close(ctx->fd);
1153
1154 free(ctx);
1155 return ret;
1156}
1157
1158static struct hw_module_methods_t hwc_module_methods = {
1159 open: hwc_device_open
1160};
1161
1162hwc_module_t HAL_MODULE_INFO_SYM = {
1163 common: {
1164 tag: HARDWARE_MODULE_TAG,
1165 version_major: 1,
1166 version_minor: 0,
1167 id: HWC_HARDWARE_MODULE_ID,
1168 name: "DRM hwcomposer module",
1169 author: "The Android Open Source Project",
1170 methods: &hwc_module_methods,
1171 dso: NULL,
1172 reserved: { 0 },
1173 }
1174};