1 /*
2 // Copyright (c) 2014 Intel Corporation
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 #include <fcntl.h>
17 #include <errno.h>
18 #include <HwcTrace.h>
19 #include <IDisplayDevice.h>
20 #include <DrmConfig.h>
21 #include <Drm.h>
22 #include <Hwcomposer.h>
23
24 namespace android {
25 namespace intel {
26
Drm()27 Drm::Drm()
28 : mDrmFd(0),
29 mLock(),
30 mInitialized(false)
31 {
32 memset(&mOutputs, 0, sizeof(mOutputs));
33 }
34
~Drm()35 Drm::~Drm()
36 {
37 WARN_IF_NOT_DEINIT();
38 }
39
initialize()40 bool Drm::initialize()
41 {
42 if (mInitialized) {
43 WTRACE("Drm object has been initialized");
44 return true;
45 }
46
47 const char *path = DrmConfig::getDrmPath();
48 mDrmFd = open(path, O_RDWR, 0);
49 if (mDrmFd < 0) {
50 ETRACE("failed to open Drm, error: %s", strerror(errno));
51 return false;
52 }
53 DTRACE("mDrmFd = %d", mDrmFd);
54
55 memset(&mOutputs, 0, sizeof(mOutputs));
56 mInitialized = true;
57 return true;
58 }
59
deinitialize()60 void Drm::deinitialize()
61 {
62 for (int i = 0; i < OUTPUT_MAX; i++) {
63 resetOutput(i);
64 }
65
66 if (mDrmFd) {
67 close(mDrmFd);
68 mDrmFd = 0;
69 }
70 mInitialized = false;
71 }
72
detect(int device)73 bool Drm::detect(int device)
74 {
75 RETURN_FALSE_IF_NOT_INIT();
76
77 Mutex::Autolock _l(mLock);
78 int outputIndex = getOutputIndex(device);
79 if (outputIndex < 0 ) {
80 return false;
81 }
82
83 resetOutput(outputIndex);
84
85 // get drm resources
86 drmModeResPtr resources = drmModeGetResources(mDrmFd);
87 if (!resources) {
88 ETRACE("fail to get drm resources, error: %s", strerror(errno));
89 return false;
90 }
91
92 drmModeConnectorPtr connector = NULL;
93 DrmOutput *output = &mOutputs[outputIndex];
94 bool ret = false;
95
96 // find connector for the given device
97 for (int i = 0; i < resources->count_connectors; i++) {
98 if (!resources->connectors || !resources->connectors[i]) {
99 ETRACE("fail to get drm resources connectors, error: %s", strerror(errno));
100 continue;
101 }
102
103 connector = drmModeGetConnector(mDrmFd, resources->connectors[i]);
104 if (!connector) {
105 ETRACE("drmModeGetConnector failed");
106 continue;
107 }
108
109 if (connector->connector_type != DrmConfig::getDrmConnector(device)) {
110 drmModeFreeConnector(connector);
111 continue;
112 }
113
114 if (connector->connection != DRM_MODE_CONNECTED) {
115 ITRACE("device %d is not connected", device);
116 drmModeFreeConnector(connector);
117 ret = true;
118 break;
119 }
120
121 output->connector = connector;
122 output->connected = true;
123
124 // get proper encoder for the given connector
125 if (connector->encoder_id) {
126 ITRACE("Drm connector has encoder attached on device %d", device);
127 output->encoder = drmModeGetEncoder(mDrmFd, connector->encoder_id);
128 if (!output->encoder) {
129 ETRACE("failed to get encoder from a known encoder id");
130 // fall through to get an encoder
131 }
132 }
133 if (!output->encoder) {
134 ITRACE("getting encoder for device %d", device);
135 drmModeEncoderPtr encoder;
136 for (int j = 0; j < resources->count_encoders; j++) {
137 if (!resources->encoders || !resources->encoders[j]) {
138 ETRACE("fail to get drm resources encoders, error: %s", strerror(errno));
139 continue;
140 }
141
142 encoder = drmModeGetEncoder(mDrmFd, resources->encoders[i]);
143 if (!encoder) {
144 ETRACE("drmModeGetEncoder failed");
145 continue;
146 }
147 if (encoder->encoder_type == DrmConfig::getDrmEncoder(device)) {
148 output->encoder = encoder;
149 break;
150 }
151 drmModeFreeEncoder(encoder);
152 encoder = NULL;
153 }
154 }
155 if (!output->encoder) {
156 ETRACE("failed to get drm encoder");
157 break;
158 }
159
160 // get an attached crtc or spare crtc
161 if (output->encoder->crtc_id) {
162 ITRACE("Drm encoder has crtc attached on device %d", device);
163 output->crtc = drmModeGetCrtc(mDrmFd, output->encoder->crtc_id);
164 if (!output->crtc) {
165 ETRACE("failed to get crtc from a known crtc id");
166 // fall through to get a spare crtc
167 }
168 }
169 if (!output->crtc) {
170 ITRACE("getting crtc for device %d", device);
171 drmModeCrtcPtr crtc;
172 for (int j = 0; j < resources->count_crtcs; j++) {
173 if (!resources->crtcs || !resources->crtcs[j]) {
174 ETRACE("fail to get drm resources crtcs, error: %s", strerror(errno));
175 continue;
176 }
177
178 crtc = drmModeGetCrtc(mDrmFd, resources->crtcs[j]);
179 if (!crtc) {
180 ETRACE("drmModeGetCrtc failed");
181 continue;
182 }
183 if (crtc->buffer_id == 0) {
184 output->crtc = crtc;
185 break;
186 }
187 drmModeFreeCrtc(crtc);
188 }
189 }
190 if (!output->crtc) {
191 ETRACE("failed to get drm crtc");
192 break;
193 }
194
195 // current mode
196 if (output->crtc->mode_valid) {
197 ITRACE("mode is valid, kernel mode settings");
198 memcpy(&output->mode, &output->crtc->mode, sizeof(drmModeModeInfo));
199 ret = true;
200 } else {
201 ITRACE("mode is invalid, setting preferred mode");
202 ret = initDrmMode(outputIndex);
203 }
204
205 if (outputIndex == OUTPUT_PRIMARY) {
206 if (!readIoctl(DRM_PSB_PANEL_ORIENTATION, &output->panelOrientation, sizeof(int))) {
207 ETRACE("failed to get device %d orientation", device);
208 output->panelOrientation = PANEL_ORIENTATION_0;
209 }
210 } else {
211 output->panelOrientation = PANEL_ORIENTATION_0;
212 }
213 break;
214 }
215
216 if (!ret) {
217 if (output->connector == NULL && outputIndex != OUTPUT_PRIMARY) {
218 // a fatal failure on primary device
219 // non fatal on secondary device
220 WTRACE("device %d is disabled?", device);
221 ret = true;
222 }
223 resetOutput(outputIndex);
224 } else if (output->connected) {
225 ITRACE("mode is: %dx%d@%dHz", output->mode.hdisplay, output->mode.vdisplay, output->mode.vrefresh);
226 }
227
228 drmModeFreeResources(resources);
229 return ret;
230 }
231
isSameDrmMode(drmModeModeInfoPtr value,drmModeModeInfoPtr base) const232 bool Drm::isSameDrmMode(drmModeModeInfoPtr value,
233 drmModeModeInfoPtr base) const
234 {
235 if (base->hdisplay == value->hdisplay &&
236 base->vdisplay == value->vdisplay &&
237 base->vrefresh == value->vrefresh &&
238 (base->flags & value->flags) == value->flags) {
239 VTRACE("Drm mode is not changed");
240 return true;
241 }
242
243 return false;
244 }
245
setDrmMode(int device,drmModeModeInfo & value)246 bool Drm::setDrmMode(int device, drmModeModeInfo& value)
247 {
248 RETURN_FALSE_IF_NOT_INIT();
249 Mutex::Autolock _l(mLock);
250
251 if (device != IDisplayDevice::DEVICE_EXTERNAL) {
252 WTRACE("Setting mode on invalid device %d", device);
253 return false;
254 }
255
256 int outputIndex = getOutputIndex(device);
257 if (outputIndex < 0 ) {
258 ETRACE("invalid device");
259 return false;
260 }
261
262 DrmOutput *output= &mOutputs[outputIndex];
263 if (!output->connected) {
264 ETRACE("device is not connected");
265 return false;
266 }
267
268 if (output->connector->count_modes <= 0) {
269 ETRACE("invalid count of modes");
270 return false;
271 }
272
273 drmModeModeInfoPtr mode;
274 int index = 0;
275 for (int i = 0; i < output->connector->count_modes; i++) {
276 mode = &output->connector->modes[i];
277 if (mode->type & DRM_MODE_TYPE_PREFERRED) {
278 index = i;
279 }
280 if (isSameDrmMode(&value, mode)) {
281 index = i;
282 break;
283 }
284 }
285
286 mode = &output->connector->modes[index];
287 return setDrmMode(outputIndex, mode);
288 }
289
setRefreshRate(int device,int hz)290 bool Drm::setRefreshRate(int device, int hz)
291 {
292 RETURN_FALSE_IF_NOT_INIT();
293 Mutex::Autolock _l(mLock);
294
295 if (device != IDisplayDevice::DEVICE_EXTERNAL) {
296 WTRACE("Setting mode on invalid device %d", device);
297 return false;
298 }
299
300 int outputIndex = getOutputIndex(device);
301 if (outputIndex < 0 ) {
302 ETRACE("invalid device");
303 return false;
304 }
305
306 DrmOutput *output= &mOutputs[outputIndex];
307 if (!output->connected) {
308 ETRACE("device is not connected");
309 return false;
310 }
311
312 if (output->connector->count_modes <= 0) {
313 ETRACE("invalid count of modes");
314 return false;
315 }
316
317 drmModeModeInfoPtr mode;
318 int index = 0;
319 for (int i = 0; i < output->connector->count_modes; i++) {
320 mode = &output->connector->modes[i];
321 if (mode->type & DRM_MODE_TYPE_PREFERRED) {
322 index = i;
323 }
324 if (mode->hdisplay == output->mode.hdisplay &&
325 mode->vdisplay == output->mode.vdisplay &&
326 mode->vrefresh == (uint32_t)hz) {
327 index = i;
328 break;
329 }
330 }
331
332 mode = &output->connector->modes[index];
333 return setDrmMode(outputIndex, mode);
334 }
335
writeReadIoctl(unsigned long cmd,void * data,unsigned long size)336 bool Drm::writeReadIoctl(unsigned long cmd, void *data,
337 unsigned long size)
338 {
339 int err;
340
341 if (mDrmFd <= 0) {
342 ETRACE("drm is not initialized");
343 return false;
344 }
345
346 if (!data || !size) {
347 ETRACE("invalid parameters");
348 return false;
349 }
350
351 err = drmCommandWriteRead(mDrmFd, cmd, data, size);
352 if (err) {
353 WTRACE("failed to call %ld ioctl with failure %d", cmd, err);
354 return false;
355 }
356
357 return true;
358 }
359
writeIoctl(unsigned long cmd,void * data,unsigned long size)360 bool Drm::writeIoctl(unsigned long cmd, void *data,
361 unsigned long size)
362 {
363 int err;
364
365 if (mDrmFd <= 0) {
366 ETRACE("drm is not initialized");
367 return false;
368 }
369
370 if (!data || !size) {
371 ETRACE("invalid parameters");
372 return false;
373 }
374
375 err = drmCommandWrite(mDrmFd, cmd, data, size);
376 if (err) {
377 WTRACE("failed to call %ld ioctl with failure %d", cmd, err);
378 return false;
379 }
380
381 return true;
382 }
383
384
readIoctl(unsigned long cmd,void * data,unsigned long size)385 bool Drm::readIoctl(unsigned long cmd, void *data,
386 unsigned long size)
387 {
388 int err;
389
390 if (mDrmFd <= 0) {
391 ETRACE("drm is not initialized");
392 return false;
393 }
394
395 if (!data || !size) {
396 ETRACE("invalid parameters");
397 return false;
398 }
399
400 err = drmCommandRead(mDrmFd, cmd, data, size);
401 if (err) {
402 WTRACE("failed to call %ld ioctl with failure %d", cmd, err);
403 return false;
404 }
405
406 return true;
407 }
408
409
getDrmFd() const410 int Drm::getDrmFd() const
411 {
412 return mDrmFd;
413 }
414
getModeInfo(int device,drmModeModeInfo & mode)415 bool Drm::getModeInfo(int device, drmModeModeInfo& mode)
416 {
417 Mutex::Autolock _l(mLock);
418
419 int outputIndex = getOutputIndex(device);
420 if (outputIndex < 0 ) {
421 return false;
422 }
423
424 DrmOutput *output= &mOutputs[outputIndex];
425 if (output->connected == false) {
426 ETRACE("device is not connected");
427 return false;
428 }
429
430 if (output->mode.hdisplay == 0 || output->mode.vdisplay == 0) {
431 ETRACE("invalid width or height");
432 return false;
433 }
434
435 memcpy(&mode, &output->mode, sizeof(drmModeModeInfo));
436 return true;
437 }
438
getPhysicalSize(int device,uint32_t & width,uint32_t & height)439 bool Drm::getPhysicalSize(int device, uint32_t& width, uint32_t& height)
440 {
441 Mutex::Autolock _l(mLock);
442
443 int outputIndex = getOutputIndex(device);
444 if (outputIndex < 0 ) {
445 return false;
446 }
447
448 DrmOutput *output= &mOutputs[outputIndex];
449 if (output->connected == false) {
450 ETRACE("device is not connected");
451 return false;
452 }
453
454 width = output->connector->mmWidth;
455 height = output->connector->mmHeight;
456 return true;
457 }
458
isConnected(int device)459 bool Drm::isConnected(int device)
460 {
461 Mutex::Autolock _l(mLock);
462
463 int output = getOutputIndex(device);
464 if (output < 0 ) {
465 return false;
466 }
467
468 return mOutputs[output].connected;
469 }
470
setDpmsMode(int device,int mode)471 bool Drm::setDpmsMode(int device, int mode)
472 {
473 Mutex::Autolock _l(mLock);
474
475 int output = getOutputIndex(device);
476 if (output < 0 ) {
477 return false;
478 }
479
480 if (mode != IDisplayDevice::DEVICE_DISPLAY_OFF &&
481 mode != IDisplayDevice::DEVICE_DISPLAY_STANDBY &&
482 mode != IDisplayDevice::DEVICE_DISPLAY_ON) {
483 ETRACE("invalid mode %d", mode);
484 return false;
485 }
486
487 DrmOutput *out = &mOutputs[output];
488 if (!out->connected) {
489 ETRACE("device is not connected");
490 return false;
491 }
492
493 drmModePropertyPtr props;
494 for (int i = 0; i < out->connector->count_props; i++) {
495 props = drmModeGetProperty(mDrmFd, out->connector->props[i]);
496 if (!props) {
497 continue;
498 }
499
500 if (strcmp(props->name, "DPMS") == 0) {
501 int ret = drmModeConnectorSetProperty(
502 mDrmFd,
503 out->connector->connector_id,
504 props->prop_id,
505 (mode == IDisplayDevice::DEVICE_DISPLAY_ON) ? DRM_MODE_DPMS_ON :
506 IDisplayDevice::DEVICE_DISPLAY_STANDBY == mode ?
507 DRM_MODE_DPMS_STANDBY : DRM_MODE_DPMS_OFF);
508 drmModeFreeProperty(props);
509 if (ret != 0) {
510 ETRACE("unable to set DPMS %d", mode);
511 return false;
512 } else {
513 return true;
514 }
515 }
516 drmModeFreeProperty(props);
517 }
518 return false;
519 }
520
resetOutput(int index)521 void Drm::resetOutput(int index)
522 {
523 DrmOutput *output = &mOutputs[index];
524
525 output->connected = false;
526 memset(&output->mode, 0, sizeof(drmModeModeInfo));
527
528 if (output->connector) {
529 drmModeFreeConnector(output->connector);
530 output->connector = 0;
531 }
532 if (output->encoder) {
533 drmModeFreeEncoder(output->encoder);
534 output->encoder = 0;
535 }
536 if (output->crtc) {
537 drmModeFreeCrtc(output->crtc);
538 output->crtc = 0;
539 }
540 if (output->fbId) {
541 drmModeRmFB(mDrmFd, output->fbId);
542 output->fbId = 0;
543 }
544 if (output->fbHandle) {
545 Hwcomposer::getInstance().getBufferManager()->freeFrameBuffer(
546 (buffer_handle_t)output->fbHandle);
547 output->fbHandle = 0;
548 }
549 }
550
initDrmMode(int outputIndex)551 bool Drm::initDrmMode(int outputIndex)
552 {
553 DrmOutput *output= &mOutputs[outputIndex];
554 if (output->connector->count_modes <= 0) {
555 ETRACE("invalid count of modes");
556 return false;
557 }
558
559 drmModeModeInfoPtr mode;
560 int index = 0;
561 for (int i = 0; i < output->connector->count_modes; i++) {
562 mode = &output->connector->modes[i];
563 if (mode->type & DRM_MODE_TYPE_PREFERRED) {
564 index = i;
565 break;
566 }
567 }
568
569 return setDrmMode(outputIndex, &output->connector->modes[index]);
570 }
571
setDrmMode(int index,drmModeModeInfoPtr mode)572 bool Drm::setDrmMode(int index, drmModeModeInfoPtr mode)
573 {
574 DrmOutput *output = &mOutputs[index];
575
576 int oldFbId =0;
577 buffer_handle_t oldFbHandle = 0;
578
579 drmModeModeInfo currentMode;
580 memcpy(¤tMode, &output->mode, sizeof(drmModeModeInfo));
581
582 if (isSameDrmMode(mode, ¤tMode))
583 return true;
584
585
586 if (output->fbId) {
587 oldFbId = output->fbId;
588 output->fbId = 0;
589 }
590
591 if (output->fbHandle) {
592 oldFbHandle = output->fbHandle;
593 output->fbHandle = 0;
594 }
595
596 // allocate frame buffer
597 int stride = 0;
598 output->fbHandle = Hwcomposer::getInstance().getBufferManager()->allocFrameBuffer(
599 mode->hdisplay, mode->vdisplay, &stride);
600 if (output->fbHandle == 0) {
601 ETRACE("failed to allocate frame buffer");
602 return false;
603 }
604
605 uint32_t bo_handles[4] = {0};
606 uint32_t pitches[4] = {0};
607 uint32_t offsets[4] = {0};
608 int ret = 0;
609
610 // We use bo_handles[0] and bo_handles[1] to store buffer_handle_t
611 // to support 32 and 64 platforms.
612 bo_handles[0] = ((unsigned long)(output->fbHandle)) & 0xffffffff;
613 bo_handles[1] = ((unsigned long)(output->fbHandle) >> 32) & 0xffffffff;
614 pitches[0] = stride * DrmConfig::getFrameBufferBpp() / 8;
615
616 ret = drmModeAddFB2(
617 mDrmFd,
618 mode->hdisplay,
619 mode->vdisplay,
620 DrmConfig::convertHalFormatToDrmFormat(DrmConfig::getFrameBufferFormat()),
621 bo_handles,
622 pitches,
623 offsets,
624 &output->fbId,
625 0);
626 if (ret != 0) {
627 ETRACE("drmModeAddFB2 failed, error: %d", ret);
628 return false;
629 }
630
631 ITRACE("mode set: %dx%d@%dHz", mode->hdisplay, mode->vdisplay, mode->vrefresh);
632
633 ret = drmModeSetCrtc(mDrmFd, output->crtc->crtc_id, output->fbId, 0, 0,
634 &output->connector->connector_id, 1, mode);
635 if (ret == 0) {
636 //save mode
637 memcpy(&output->mode, mode, sizeof(drmModeModeInfo));
638 } else {
639 ETRACE("drmModeSetCrtc failed. error: %d", ret);
640 }
641
642 if (oldFbId) {
643 drmModeRmFB(mDrmFd, oldFbId);
644 }
645
646 if (oldFbHandle) {
647 Hwcomposer::getInstance().getBufferManager()->freeFrameBuffer((buffer_handle_t)oldFbHandle);
648 }
649
650 return ret == 0;
651 }
652
getOutputIndex(int device)653 int Drm::getOutputIndex(int device)
654 {
655 switch (device) {
656 case IDisplayDevice::DEVICE_PRIMARY:
657 return OUTPUT_PRIMARY;
658 case IDisplayDevice::DEVICE_EXTERNAL:
659 return OUTPUT_EXTERNAL;
660 default:
661 ETRACE("invalid display device");
662 break;
663 }
664
665 return -1;
666 }
667
getPanelOrientation(int device)668 int Drm::getPanelOrientation(int device)
669 {
670 int outputIndex = getOutputIndex(device);
671 if (outputIndex < 0) {
672 ETRACE("invalid device");
673 return PANEL_ORIENTATION_0;
674 }
675
676 DrmOutput *output= &mOutputs[outputIndex];
677 if (output->connected == false) {
678 ETRACE("device is not connected");
679 return PANEL_ORIENTATION_0;
680 }
681
682 return output->panelOrientation;
683 }
684
685 // HWC 1.4 requires that we return all of the compatible configs in getDisplayConfigs
686 // this is needed so getActiveConfig/setActiveConfig work correctly. It is up to the
687 // user space to decide what speed to send.
detectAllConfigs(int device,int * modeCount)688 drmModeModeInfoPtr Drm::detectAllConfigs(int device, int *modeCount)
689 {
690 RETURN_NULL_IF_NOT_INIT();
691 Mutex::Autolock _l(mLock);
692
693 if (modeCount != NULL)
694 *modeCount = 0;
695 else
696 return NULL;
697
698 int outputIndex = getOutputIndex(device);
699 if (outputIndex < 0) {
700 ETRACE("invalid device");
701 return NULL;
702 }
703
704 DrmOutput *output= &mOutputs[outputIndex];
705 if (!output->connected) {
706 ETRACE("device is not connected");
707 return NULL;
708 }
709
710 if (output->connector->count_modes <= 0) {
711 ETRACE("invalid count of modes");
712 return NULL;
713 }
714
715 *modeCount = output->connector->count_modes;
716 return output->connector->modes;
717 }
718
719 } // namespace intel
720 } // namespace android
721
722