• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&currentMode, &output->mode, sizeof(drmModeModeInfo));
581 
582     if (isSameDrmMode(mode, &currentMode))
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