Home | History | Annotate | Download | only in base
      1 /*
      2 // Copyright(c)2014 IntelCorporation
      3 //
      4 // LicensedundertheApacheLicense,Version2.0(the"License");
      5 // youmaynotusethisfileexceptincompliancewiththeLicense.
      6 // YoumayobtainacopyoftheLicenseat
      7 //
      8 // http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unlessrequiredbyapplicablelaworagreedtoinwriting,software
     11 // distributedundertheLicenseisdistributedonan"ASIS"BASIS,
     12 // WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.
     13 // SeetheLicenseforthespecificlanguagegoverningpermissionsand
     14 // limitationsundertheLicense.
     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 
     27 Drm::Drm()
     28     : mDrmFd(0),
     29       mLock(),
     30       mInitialized(false)
     31 {
     32     memset(&mOutputs, 0, sizeof(mOutputs));
     33 }
     34 
     35 Drm::~Drm()
     36 {
     37     WARN_IF_NOT_DEINIT();
     38 }
     39 
     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 
     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 
     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 
    232 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 
    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 
    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 
    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 
    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 
    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 
    410 int Drm::getDrmFd() const
    411 {
    412     return mDrmFd;
    413 }
    414 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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.
    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