1 /* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. 2 * 3 * Redistribution and use in source and binary forms, with or without 4 * modification, are permitted provided that the following conditions are 5 * met: 6 * * Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * * Redistributions in binary form must reproduce the above 9 * copyright notice, this list of conditions and the following 10 * disclaimer in the documentation and/or other materials provided 11 * with the distribution. 12 * * Neither the name of The Linux Foundation nor the names of its 13 * contributors may be used to endorse or promote products derived 14 * from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 */ 29 30 #define LOG_TAG "QCameraPerf" 31 32 // To remove 33 #include <cutils/properties.h> 34 #include <utils/Errors.h> 35 36 // System dependencies 37 #include <stdlib.h> 38 #include <dlfcn.h> 39 #include <utils/Timers.h> 40 // Camera dependencies 41 #include "QCameraPerf.h" 42 #include "QCameraTrace.h" 43 44 #include <android-base/properties.h> 45 46 extern "C" { 47 #include "mm_camera_dbg.h" 48 } 49 50 namespace qcamera { 51 52 typedef enum { 53 MPCTLV3_MIN_FREQ_CLUSTER_BIG_CORE_0 = 0x40800000, 54 MPCTLV3_MIN_FREQ_CLUSTER_BIG_CORE_1 = 0x40800010, 55 MPCTLV3_MIN_FREQ_CLUSTER_BIG_CORE_2 = 0x40800020, 56 MPCTLV3_MIN_FREQ_CLUSTER_BIG_CORE_3 = 0x40800030, 57 MPCTLV3_MIN_FREQ_CLUSTER_LITTLE_CORE_0 = 0x40800100, 58 MPCTLV3_MIN_FREQ_CLUSTER_LITTLE_CORE_1 = 0x40800110, 59 MPCTLV3_MIN_FREQ_CLUSTER_LITTLE_CORE_2 = 0x40800120, 60 MPCTLV3_MIN_FREQ_CLUSTER_LITTLE_CORE_3 = 0x40800130, 61 62 MPCTLV3_MAX_FREQ_CLUSTER_BIG_CORE_0 = 0x40804000, 63 MPCTLV3_MAX_FREQ_CLUSTER_BIG_CORE_1 = 0x40804010, 64 MPCTLV3_MAX_FREQ_CLUSTER_BIG_CORE_2 = 0x40804020, 65 MPCTLV3_MAX_FREQ_CLUSTER_BIG_CORE_3 = 0x40804030, 66 MPCTLV3_MAX_FREQ_CLUSTER_LITTLE_CORE_0 = 0x40804100, 67 MPCTLV3_MAX_FREQ_CLUSTER_LITTLE_CORE_1 = 0x40804110, 68 MPCTLV3_MAX_FREQ_CLUSTER_LITTLE_CORE_2 = 0x40804120, 69 MPCTLV3_MAX_FREQ_CLUSTER_LITTLE_CORE_3 = 0x40804130, 70 71 MPCTLV3_MIN_ONLINE_CPU_CLUSTER_BIG = 0x41000000, 72 MPCTLV3_MIN_ONLINE_CPU_CLUSTER_LITTLE = 0x41000100, 73 MPCTLV3_MAX_ONLINE_CPU_CLUSTER_BIG = 0x41004000, 74 MPCTLV3_MAX_ONLINE_CPU_CLUSTER_LITTLE = 0x41004100, 75 76 MPCTLV3_ALL_CPUS_PWR_CLPS_DIS = 0x40400000, 77 MPCTLV3_CPUBW_HWMON_MIN_FREQ = 0x41800000, 78 MPCTLV3_CPUBW_HWMON_HYST_OPT = 0x4180C000 79 } perf_lock_params; 80 81 82 static int32_t perfLockParamsOpenCamera[] = { 83 // Disable power collapse and set CPU cloks to turbo 84 MPCTLV3_ALL_CPUS_PWR_CLPS_DIS, 0x1, 85 MPCTLV3_MAX_FREQ_CLUSTER_BIG_CORE_0, 0xFFF, 86 MPCTLV3_MIN_FREQ_CLUSTER_BIG_CORE_0, 0xFFF, 87 MPCTLV3_MAX_FREQ_CLUSTER_LITTLE_CORE_0, 0xFFF, 88 MPCTLV3_MIN_FREQ_CLUSTER_LITTLE_CORE_0, 0xFFF 89 }; 90 91 static int32_t perfLockParamsCloseCamera[] = { 92 // Disable power collapse and set CPU cloks to turbo 93 MPCTLV3_ALL_CPUS_PWR_CLPS_DIS, 0x1, 94 MPCTLV3_MAX_FREQ_CLUSTER_BIG_CORE_0, 0xFFF, 95 MPCTLV3_MIN_FREQ_CLUSTER_BIG_CORE_0, 0xFFF, 96 MPCTLV3_MAX_FREQ_CLUSTER_LITTLE_CORE_0, 0xFFF, 97 MPCTLV3_MIN_FREQ_CLUSTER_LITTLE_CORE_0, 0xFFF 98 }; 99 100 static int32_t perfLockParamsStartPreview[] = { 101 // Disable power collapse and set CPU cloks to turbo 102 MPCTLV3_ALL_CPUS_PWR_CLPS_DIS, 0x1, 103 MPCTLV3_MAX_FREQ_CLUSTER_BIG_CORE_0, 0xFFF, 104 MPCTLV3_MIN_FREQ_CLUSTER_BIG_CORE_0, 0xFFF, 105 MPCTLV3_MAX_FREQ_CLUSTER_LITTLE_CORE_0, 0xFFF, 106 MPCTLV3_MIN_FREQ_CLUSTER_LITTLE_CORE_0, 0xFFF 107 }; 108 109 static int32_t perfLockParamsTakeSnapshot[] = { 110 // Disable power collapse and set CPU cloks to turbo 111 MPCTLV3_ALL_CPUS_PWR_CLPS_DIS, 0x1, 112 MPCTLV3_MAX_FREQ_CLUSTER_BIG_CORE_0, 0xFFF, 113 MPCTLV3_MIN_FREQ_CLUSTER_BIG_CORE_0, 0xFFF, 114 MPCTLV3_MAX_FREQ_CLUSTER_LITTLE_CORE_0, 0xFFF, 115 MPCTLV3_MIN_FREQ_CLUSTER_LITTLE_CORE_0, 0xFFF, 116 MPCTLV3_CPUBW_HWMON_HYST_OPT, 0x0, 117 MPCTLV3_CPUBW_HWMON_MIN_FREQ, 0x8C 118 }; 119 120 PerfLockInfo QCameraPerfLock::mPerfLockInfo[] = { 121 { //PERF_LOCK_OPEN_CAMERA 122 perfLockParamsOpenCamera, 123 sizeof(perfLockParamsOpenCamera)/sizeof(int32_t) }, 124 { //PERF_LOCK_CLOSE_CAMERA 125 perfLockParamsCloseCamera, 126 sizeof(perfLockParamsCloseCamera)/sizeof(int32_t) }, 127 { //PERF_LOCK_START_PREVIEW 128 perfLockParamsStartPreview, 129 sizeof(perfLockParamsStartPreview)/sizeof(int32_t) }, 130 { //PERF_LOCK_TAKE_SNAPSHOT 131 perfLockParamsTakeSnapshot, 132 sizeof(perfLockParamsTakeSnapshot)/sizeof(int32_t) }, 133 { //PERF_LOCK_POWERHINT_PREVIEW 134 NULL, 0}, 135 { //PERF_LOCK_POWERHINT_ENCODE 136 NULL, 0} 137 }; 138 139 Mutex QCameraPerfLockIntf::mMutex; 140 QCameraPerfLockIntf* QCameraPerfLockIntf::mInstance = NULL; 141 142 143 /*=========================================================================== 144 * FUNCTION : QCameraPerfLockMgr constructor 145 * 146 * DESCRIPTION: Initialize the perf locks 147 * 148 * PARAMETERS : None 149 * 150 * RETURN : void 151 * 152 *==========================================================================*/ 153 QCameraPerfLockMgr::QCameraPerfLockMgr() : 154 mState(LOCK_MGR_STATE_UNINITIALIZED) 155 { 156 for (int i = 0; i < PERF_LOCK_COUNT; ++i) { 157 mPerfLock[i] = QCameraPerfLock::create((PerfLockEnum)i); 158 159 if (mPerfLock[i] == NULL) { 160 mState = LOCK_MGR_STATE_ERROR; 161 LOGE("Could not allocate perf locks"); 162 163 // Set the remaining perf locks to NULL 164 for (int j = i+1; j < PERF_LOCK_COUNT; ++j) { 165 mPerfLock[j] = NULL; 166 } 167 return; 168 } 169 } 170 mState = LOCK_MGR_STATE_READY; 171 } 172 173 174 /*=========================================================================== 175 * FUNCTION : QCameraPerfLockMgr destructor 176 * 177 * DESCRIPTION: class destructor 178 * 179 * PARAMETERS : None 180 * 181 * RETURN : void 182 * 183 *==========================================================================*/ 184 QCameraPerfLockMgr::~QCameraPerfLockMgr() 185 { 186 for (int i = 0; i < PERF_LOCK_COUNT; ++i) { 187 if (mPerfLock[i]) { 188 delete mPerfLock[i]; 189 } 190 } 191 } 192 193 194 /*=========================================================================== 195 * FUNCTION : acquirePerfLock 196 * 197 * DESCRIPTION: Call acquirePerfLock function for the requested perf lock 198 * 199 * PARAMETERS : 200 * @perfLockType: Perf lock enum 201 * @timer: Timer value in ms 202 * 203 * RETURN : true on success 204 * false on failure 205 *==========================================================================*/ 206 bool QCameraPerfLockMgr::acquirePerfLock( 207 PerfLockEnum perfLockType, 208 uint32_t timer) 209 { 210 bool ret = false; 211 if ((mState == LOCK_MGR_STATE_READY) && 212 isValidPerfLockEnum(perfLockType)) { 213 ret = mPerfLock[perfLockType]->acquirePerfLock(true, timer); 214 } 215 return ret; 216 } 217 218 219 /*=========================================================================== 220 * FUNCTION : acquirePerfLockIfExpired 221 * 222 * DESCRIPTION: Call acquirePerfLock function for the requested perf lock 223 * 224 * PARAMETERS : 225 * @perfLockType: Type of perf lock 226 * @timer: Timer value in ms 227 * 228 * RETURN : true on success 229 * false on failure 230 *==========================================================================*/ 231 bool QCameraPerfLockMgr::acquirePerfLockIfExpired( 232 PerfLockEnum perfLockType, 233 uint32_t timer) 234 { 235 bool ret = false; 236 if ((mState == LOCK_MGR_STATE_READY) && 237 isValidPerfLockEnum(perfLockType)) { 238 ret = mPerfLock[perfLockType]->acquirePerfLock(false, timer); 239 } 240 return ret; 241 242 } 243 244 245 /*=========================================================================== 246 * FUNCTION : releasePerfLock 247 * 248 * DESCRIPTION: Call releasePerfLock function for the requested perf lock 249 * 250 * PARAMETERS : 251 * @perfLockType: Enum of perf lock 252 * 253 * RETURN : true on success 254 * false on failure 255 *==========================================================================*/ 256 bool QCameraPerfLockMgr::releasePerfLock( 257 PerfLockEnum perfLockType) 258 { 259 bool ret = false; 260 if ((mState == LOCK_MGR_STATE_READY) && 261 isValidPerfLockEnum(perfLockType)) { 262 ret = mPerfLock[perfLockType]->releasePerfLock(); 263 } 264 return ret; 265 } 266 267 268 /*=========================================================================== 269 * FUNCTION : powerHintInternal 270 * 271 * DESCRIPTION: Calls the appropriate perf lock's powerHintInternal function 272 * 273 * PARAMETERS : 274 * @perfLockType: Type of perf lock 275 * @hint : Power hint 276 * @enable : Enable power hint if set to 1. Disable if set to 0. 277 * 278 * RETURN : void 279 * 280 *==========================================================================*/ 281 void QCameraPerfLockMgr::powerHintInternal( 282 PerfLockEnum perfLockType, 283 PowerHint powerHint, 284 bool enable) 285 { 286 if ((mState == LOCK_MGR_STATE_READY) && 287 isValidPerfLockEnum(perfLockType)) { 288 mPerfLock[perfLockType]->powerHintInternal(powerHint, enable); 289 } 290 } 291 292 293 /*=========================================================================== 294 * FUNCTION : create 295 * 296 * DESCRIPTION: This is a static method to create perf lock object. It calls 297 * protected constructor of the class and only returns a valid object 298 * if it can successfully initialize the perf lock. 299 * 300 * PARAMETERS : None 301 * 302 * RETURN : QCameraPerfLock object pointer on success 303 * NULL on failure 304 * 305 *==========================================================================*/ 306 QCameraPerfLock* QCameraPerfLock::create( 307 PerfLockEnum perfLockType) 308 { 309 QCameraPerfLock *perfLock = NULL; 310 311 if (perfLockType < PERF_LOCK_COUNT) { 312 QCameraPerfLockIntf *perfLockIntf = QCameraPerfLockIntf::createSingleton(); 313 if (perfLockIntf) { 314 perfLock = new QCameraPerfLock(perfLockType, perfLockIntf); 315 } 316 } 317 return perfLock; 318 } 319 320 321 /*=========================================================================== 322 * FUNCTION : QCameraPerfLock constructor 323 * 324 * DESCRIPTION: Initialize member variables 325 * 326 * PARAMETERS : None 327 * 328 * RETURN : void 329 * 330 *==========================================================================*/ 331 QCameraPerfLock::QCameraPerfLock( 332 PerfLockEnum perfLockType, 333 QCameraPerfLockIntf *perfLockIntf) : 334 mHandle(0), 335 mRefCount(0), 336 mTimeOut(0), 337 mPerfLockType(perfLockType), 338 mPerfLockIntf(perfLockIntf) 339 { 340 mIsPerfdEnabled = android::base::GetBoolProperty("persist.camera.perfd.enable", false); 341 } 342 343 344 /*=========================================================================== 345 * FUNCTION : QCameraPerfLock destructor 346 * 347 * DESCRIPTION: class destructor 348 * 349 * PARAMETERS : None 350 * 351 * RETURN : void 352 * 353 *==========================================================================*/ 354 QCameraPerfLock::~QCameraPerfLock() 355 { 356 if (mHandle > 0) { 357 (*mPerfLockIntf->perfLockRel())(mHandle); 358 } 359 QCameraPerfLockIntf::deleteInstance(); 360 } 361 362 363 /*=========================================================================== 364 * FUNCTION : isTimedOut 365 * 366 * DESCRIPTION: Check if the perf lock is timed out 367 * 368 * PARAMETERS : None 369 * 370 * RETURN : boolean indicating if the perf lock is timed out 371 * 372 *==========================================================================*/ 373 bool QCameraPerfLock::isTimedOut() 374 { 375 if (mTimeOut && (systemTime() > mTimeOut)) { 376 return true; 377 } 378 return false; 379 } 380 381 382 /*=========================================================================== 383 * FUNCTION : restartTimer 384 * 385 * DESCRIPTION: Restart the timer for the duration specified 386 * 387 * PARAMETERS : 388 * @timer : timer duration in milliseconds 389 * 390 * RETURN : void 391 * 392 *==========================================================================*/ 393 void inline QCameraPerfLock::restartTimer( 394 uint32_t timer) 395 { 396 if (timer > 0) { 397 mTimeOut = systemTime() + ms2ns(timer); 398 } 399 } 400 401 402 /*=========================================================================== 403 * FUNCTION : acquirePerfLock 404 * 405 * DESCRIPTION: Acquires the perf lock for the duration specified. Do not acquire 406 * the perf lock is reacquire flag is set to false provided the perf 407 * lock is already acquired. 408 * 409 * PARAMETERS : 410 * @forceReaquirePerfLock: Reacquire 411 * @timer : Duration of the perf lock 412 * 413 * RETURN : true on success 414 * false on failure 415 * 416 *==========================================================================*/ 417 bool QCameraPerfLock::acquirePerfLock( 418 bool forceReaquirePerfLock, 419 uint32_t timer) 420 { 421 bool ret = true; 422 Mutex::Autolock lock(mMutex); 423 424 if ((mPerfLockType == PERF_LOCK_POWERHINT_PREVIEW) || 425 (mPerfLockType == PERF_LOCK_POWERHINT_ENCODE)) { 426 powerHintInternal(PowerHint::VIDEO_ENCODE, true); 427 return true; 428 } 429 430 if (!mIsPerfdEnabled) return ret; 431 432 if (isTimedOut()) { 433 mHandle = 0; 434 mRefCount = 0; 435 } 436 437 if ((mRefCount == 0) || forceReaquirePerfLock) { 438 mHandle = (*mPerfLockIntf->perfLockAcq())( 439 mHandle, timer, 440 mPerfLockInfo[mPerfLockType].perfLockParams, 441 mPerfLockInfo[mPerfLockType].perfLockParamsCount); 442 443 if (mHandle > 0) { 444 ++mRefCount; 445 restartTimer(timer); 446 LOGD("perfLockHandle %d, updated refCount: %d, perfLockType: %d", 447 mHandle, mRefCount, mPerfLockType); 448 } else { 449 LOGE("Failed to acquire the perf lock"); 450 ret = false; 451 } 452 } else { 453 LOGD("Perf lock already acquired, not re-aquiring"); 454 } 455 456 return ret; 457 } 458 459 460 /*=========================================================================== 461 * FUNCTION : releasePerfLock 462 * 463 * DESCRIPTION: Releases the perf lock 464 * 465 * PARAMETERS : None 466 * 467 * RETURN : true on success 468 * false on failure 469 * 470 *==========================================================================*/ 471 bool QCameraPerfLock::releasePerfLock() 472 { 473 bool ret = true; 474 Mutex::Autolock lock(mMutex); 475 476 if ((mPerfLockType == PERF_LOCK_POWERHINT_PREVIEW) || 477 (mPerfLockType == PERF_LOCK_POWERHINT_ENCODE)) { 478 powerHintInternal(PowerHint::VIDEO_ENCODE, false); 479 return true; 480 } 481 482 if (!mIsPerfdEnabled) return ret; 483 484 if (mHandle > 0) { 485 LOGD("perfLockHandle %d, refCount: %d, perfLockType: %d", 486 mHandle, mRefCount, mPerfLockType); 487 488 if (isTimedOut()) { 489 mHandle = 0; 490 mRefCount = 0; 491 } else if (--mRefCount == 0) { 492 int32_t rc = (*mPerfLockIntf->perfLockRel())(mHandle); 493 mHandle = 0; 494 mTimeOut = 0; 495 if (rc < 0) { 496 LOGE("Failed to release the perf lock"); 497 ret = false; 498 } 499 } 500 } else { 501 LOGW("Perf lock %d either not acquired or already released", mPerfLockType); 502 } 503 504 return ret; 505 } 506 507 508 /*=========================================================================== 509 * FUNCTION : powerHintInternal 510 * 511 * DESCRIPTION: Sets the requested power hint and state to power HAL. 512 * 513 * PARAMETERS : 514 * @hint : Power hint 515 * @enable : Enable power hint if set to 1. Disable if set to 0. 516 * 517 * RETURN : void 518 * 519 *==========================================================================*/ 520 void QCameraPerfLock::powerHintInternal( 521 PowerHint powerHint, 522 bool enable) 523 { 524 #ifdef HAS_MULTIMEDIA_HINTS 525 if (!mPerfLockIntf->powerHint(powerHint, enable)) { 526 LOGE("Send powerhint to PowerHal failed"); 527 } 528 #endif 529 } 530 531 532 533 /*=========================================================================== 534 * FUNCTION : createSingleton 535 * 536 * DESCRIPTION: Open the perf lock library, query the function pointers and 537 * create a singleton object upon success 538 * 539 * PARAMETERS : None 540 * 541 * RETURN : QCameraPerfLockIntf object pointer on success 542 * NULL on failure 543 * 544 *==========================================================================*/ 545 QCameraPerfLockIntf* QCameraPerfLockIntf::createSingleton() 546 { 547 bool error = true; 548 Mutex::Autolock lock(mMutex); 549 550 if (mInstance == NULL) { 551 // Open perflock library and query for the function pointers 552 uint32_t perfLockEnable = 0; 553 char value[PROPERTY_VALUE_MAX]; 554 555 property_get("persist.camera.perflock.enable", value, "1"); 556 perfLockEnable = atoi(value); 557 558 if (perfLockEnable) { 559 mInstance = new QCameraPerfLockIntf(); 560 if (mInstance) { 561 #ifdef HAS_MULTIMEDIA_HINTS 562 mInstance->mPowerHal = IPower::getService(); 563 if (mInstance->mPowerHal == nullptr) { 564 ALOGE("Couldn't load PowerHAL module"); 565 } 566 else 567 #endif 568 { 569 /* Retrieve the name of the vendor extension library */ 570 void *dlHandle = NULL; 571 if ((property_get("ro.vendor.extension_library", value, NULL) > 0) && 572 (dlHandle = dlopen(value, RTLD_NOW | RTLD_LOCAL))) { 573 574 perfLockAcquire pLockAcq = (perfLockAcquire)dlsym(dlHandle, "perf_lock_acq"); 575 perfLockRelease pLockRel = (perfLockRelease)dlsym(dlHandle, "perf_lock_rel"); 576 577 if (pLockAcq && pLockRel) { 578 mInstance->mDlHandle = dlHandle; 579 mInstance->mPerfLockAcq = pLockAcq; 580 mInstance->mPerfLockRel = pLockRel; 581 error = false; 582 } else { 583 LOGE("Failed to link the symbols- perf_lock_acq, perf_lock_rel"); 584 } 585 } else { 586 LOGE("Unable to load lib: %s", value); 587 } 588 } 589 if (error && mInstance) { 590 delete mInstance; 591 mInstance = NULL; 592 } 593 } 594 } 595 } 596 597 if (mInstance) { 598 ++(mInstance->mRefCount); 599 } 600 601 return mInstance; 602 } 603 604 605 /*=========================================================================== 606 * FUNCTION : deleteInstance 607 * 608 * DESCRIPTION: Delete the object if refCount is 0 609 * 610 * PARAMETERS : None 611 * 612 * RETURN : void 613 * 614 *==========================================================================*/ 615 void QCameraPerfLockIntf::deleteInstance() 616 { 617 Mutex::Autolock lock(mMutex); 618 619 if (mInstance && (--(mInstance->mRefCount) == 0)) { 620 delete mInstance; 621 mInstance = NULL; 622 } 623 } 624 625 626 /*=========================================================================== 627 * FUNCTION : QCameraPerfLockIntf destructor 628 * 629 * DESCRIPTION: class destructor 630 * 631 * PARAMETERS : None 632 * 633 * RETURN : void 634 * 635 *==========================================================================*/ 636 QCameraPerfLockIntf::~QCameraPerfLockIntf() 637 { 638 if (mDlHandle) { 639 dlclose(mDlHandle); 640 } 641 } 642 643 }; // namespace qcamera 644