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(¤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 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