/* Copyright (c) 2015, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of The Linux Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #define LOG_TAG "QCameraPerf" #include <cutils/properties.h> #include <stdlib.h> #include <utils/Log.h> #include "QCameraPerf.h" #ifdef CDBG #undef CDBG #endif //#ifdef CDBG #define CDBG(fmt, args...) ALOGD_IF(gCamHalLogLevel >= 2, fmt, ##args) #ifdef CDBG_HIGH #undef CDBG_HIGH #endif //#ifdef CDBG_HIGH #define CDBG_HIGH(fmt, args...) ALOGD_IF(gCamHalLogLevel >= 1, fmt, ##args) namespace qcamera { extern volatile uint32_t gCamHalLogLevel; /*=========================================================================== * FUNCTION : QCameraPerfLock constructor * * DESCRIPTION: initialize member variables * * PARAMETERS : * None * * RETURN : void * *==========================================================================*/ QCameraPerfLock::QCameraPerfLock() : perf_lock_acq(NULL), perf_lock_rel(NULL), mDlHandle(NULL), mPerfLockEnable(0), mPerfLockHandle(-1), mPerfLockHandleTimed(-1), mTimerSet(0), mPerfLockTimeout(0), mStartTimeofLock(0) { } /*=========================================================================== * FUNCTION : QCameraPerfLock destructor * * DESCRIPTION: class desctructor * * PARAMETERS : * None * * RETURN : void * *==========================================================================*/ QCameraPerfLock::~QCameraPerfLock() { lock_deinit(); } /*=========================================================================== * FUNCTION : lock_init * * DESCRIPTION: opens the performance lib and initilizes the perf lock functions * * PARAMETERS : * None * * RETURN : void * *==========================================================================*/ void QCameraPerfLock::lock_init() { const char *rc; char value[PROPERTY_VALUE_MAX]; int len; CDBG("%s E", __func__); Mutex::Autolock lock(mLock); property_get("persist.camera.perflock.enable", value, "1"); mPerfLockEnable = atoi(value); mCurrentPowerHintEnable = 0; #ifdef HAS_MULTIMEDIA_HINTS if (hw_get_module(POWER_HARDWARE_MODULE_ID, (const hw_module_t **)&m_pPowerModule)) { ALOGE("%s: %s module not found", __func__, POWER_HARDWARE_MODULE_ID); } #endif if (mPerfLockEnable) { perf_lock_acq = NULL; perf_lock_rel = NULL; mPerfLockHandle = -1; /* Retrieve name of vendor extension library */ if (property_get("ro.vendor.extension_library", value, NULL) <= 0) { goto cleanup; } mDlHandle = dlopen(value, RTLD_NOW | RTLD_LOCAL); if (mDlHandle == NULL) { goto cleanup; } dlerror(); perf_lock_acq = (int (*) (int, int, int[], int))dlsym(mDlHandle, "perf_lock_acq"); if ((rc = dlerror()) != NULL) { ALOGE("%s: failed to perf_lock_acq function handle", __func__); goto cleanup; } perf_lock_rel = (int (*) (int))dlsym(mDlHandle, "perf_lock_rel"); if ((rc = dlerror()) != NULL) { ALOGE("%s: failed to perf_lock_rel function handle", __func__); goto cleanup; } CDBG("%s X", __func__); return; cleanup: perf_lock_acq = NULL; perf_lock_rel = NULL; mPerfLockEnable = 0; if (mDlHandle) { dlclose(mDlHandle); mDlHandle = NULL; } } CDBG("%s X", __func__); } /*=========================================================================== * FUNCTION : lock_deinit * * DESCRIPTION: deinitialize the perf lock parameters * * PARAMETERS : * None * * RETURN : void * *==========================================================================*/ void QCameraPerfLock::lock_deinit() { Mutex::Autolock lock(mLock); if (mPerfLockEnable) { CDBG("%s E", __func__); if (mDlHandle) { perf_lock_acq = NULL; perf_lock_rel = NULL; dlclose(mDlHandle); mDlHandle = NULL; } mPerfLockEnable = 0; CDBG("%s X", __func__); } } /*=========================================================================== * FUNCTION : isTimerReset * * DESCRIPTION: Check if timout duration is reached * * PARAMETERS : None * * RETURN : true if timeout reached * false if timeout not reached * *==========================================================================*/ bool QCameraPerfLock::isTimerReset() { Mutex::Autolock lock(mLock); if (mPerfLockEnable && mTimerSet) { nsecs_t timeDiff = systemTime() - mStartTimeofLock; if (ns2ms(timeDiff) > (uint32_t)mPerfLockTimeout) { mTimerSet = 0; return true; } } return false; } /*=========================================================================== * FUNCTION : start_timer * * DESCRIPTION: get the start of the timer * * PARAMETERS : * @timer_val: timer duration in milliseconds * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code * *==========================================================================*/ void QCameraPerfLock::startTimer(uint32_t timer_val) { mStartTimeofLock = systemTime(); mTimerSet = 1; mPerfLockTimeout = timer_val; } /*=========================================================================== * FUNCTION : lock_acq_timed * * DESCRIPTION: Acquire the performance lock for the specified duration. * If an existing lock timeout has not elapsed, extend the * lock further for the specified duration * * PARAMETERS : * @timer_val: lock duration * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code * *==========================================================================*/ int32_t QCameraPerfLock::lock_acq_timed(int32_t timer_val) { int32_t ret = -1; CDBG("%s E", __func__); Mutex::Autolock lock(mLock); if (mPerfLockEnable) { int32_t perf_lock_params[] = { ALL_CPUS_PWR_CLPS_DIS, CPU0_MIN_FREQ_TURBO_MAX, CPU4_MIN_FREQ_TURBO_MAX }; if (mTimerSet) { nsecs_t curElapsedTime = systemTime() - mStartTimeofLock; int32_t pendingTimeout = mPerfLockTimeout - ns2ms(curElapsedTime); timer_val += pendingTimeout; } startTimer(timer_val); // Disable power hint when acquiring the perf lock if (mCurrentPowerHintEnable) { CDBG_HIGH("%s mCurrentPowerHintEnable %d", __func__ ,mCurrentPowerHintEnable); powerHintInternal(mCurrentPowerHint, 0); } if ((NULL != perf_lock_acq) && (mPerfLockHandleTimed < 0)) { ret = (*perf_lock_acq)(mPerfLockHandleTimed, timer_val, perf_lock_params, sizeof(perf_lock_params) / sizeof(int32_t)); CDBG("%s ret %d", __func__, ret); if (ret < 0) { ALOGE("%s: failed to acquire lock", __func__); } else { mPerfLockHandleTimed = ret; } } CDBG("%s perf_handle_acq %d ",__func__, mPerfLockHandleTimed); } CDBG("%s X", __func__); return ret; } /*=========================================================================== * FUNCTION : lock_acq * * DESCRIPTION: acquire the performance lock * * PARAMETERS : * None * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code * *==========================================================================*/ int32_t QCameraPerfLock::lock_acq() { int32_t ret = -1; CDBG("%s E", __func__); Mutex::Autolock lock(mLock); if (mPerfLockEnable) { int32_t perf_lock_params[] = { ALL_CPUS_PWR_CLPS_DIS, CPU0_MIN_FREQ_TURBO_MAX, CPU4_MIN_FREQ_TURBO_MAX }; // Disable power hint when acquiring the perf lock if (mCurrentPowerHintEnable) { powerHintInternal(mCurrentPowerHint, 0); } if ((NULL != perf_lock_acq) && (mPerfLockHandle < 0)) { ret = (*perf_lock_acq)(mPerfLockHandle, ONE_SEC, perf_lock_params, sizeof(perf_lock_params) / sizeof(int32_t)); CDBG("%s ret %d", __func__, ret); if (ret < 0) { ALOGE("%s: failed to acquire lock", __func__); } else { mPerfLockHandle = ret; } } CDBG("%s perf_handle_acq %d ",__func__, mPerfLockHandle); } CDBG("%s X", __func__); return ret; } /*=========================================================================== * FUNCTION : lock_rel_timed * * DESCRIPTION: release the performance lock * * PARAMETERS : * None * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code * *==========================================================================*/ int32_t QCameraPerfLock::lock_rel_timed() { int ret = -1; Mutex::Autolock lock(mLock); if (mPerfLockEnable) { CDBG("%s E", __func__); if (mPerfLockHandleTimed < 0) { ALOGE("%s: mPerfLockHandle < 0,check if lock is acquired", __func__); return ret; } CDBG("%s perf_handle_rel %d ",__func__, mPerfLockHandleTimed); if ((NULL != perf_lock_rel) && (0 <= mPerfLockHandleTimed)) { ret = (*perf_lock_rel)(mPerfLockHandleTimed); if (ret < 0) { ALOGE("%s: failed to release lock", __func__); } mPerfLockHandleTimed = -1; } if ((mCurrentPowerHintEnable == 1) && (mTimerSet == 0)) { powerHintInternal(mCurrentPowerHint, mCurrentPowerHintEnable); } CDBG("%s X", __func__); } return ret; } /*=========================================================================== * FUNCTION : lock_rel * * DESCRIPTION: release the performance lock * * PARAMETERS : * None * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code * *==========================================================================*/ int32_t QCameraPerfLock::lock_rel() { int ret = -1; Mutex::Autolock lock(mLock); if (mPerfLockEnable) { CDBG("%s E", __func__); if (mPerfLockHandle < 0) { ALOGE("%s: mPerfLockHandle < 0,check if lock is acquired", __func__); return ret; } CDBG("%s perf_handle_rel %d ",__func__, mPerfLockHandle); if ((NULL != perf_lock_rel) && (0 <= mPerfLockHandle)) { ret = (*perf_lock_rel)(mPerfLockHandle); if (ret < 0) { ALOGE("%s: failed to release lock", __func__); } mPerfLockHandle = -1; } if ((mCurrentPowerHintEnable == 1) && (mTimerSet == 0)) { powerHintInternal(mCurrentPowerHint, mCurrentPowerHintEnable); } CDBG("%s X", __func__); } return ret; } /*=========================================================================== * FUNCTION : powerHintInternal * * DESCRIPTION: Sets the requested power hint and state to power HAL. * * PARAMETERS : * enable : Enable power hint if set to 1. Disable if set to 0. * RETURN : void * *==========================================================================*/ void QCameraPerfLock::powerHintInternal(power_hint_t hint, uint32_t enable) { #ifdef HAS_MULTIMEDIA_HINTS if (m_pPowerModule != NULL) { if (enable == 1) { m_pPowerModule->powerHint(m_pPowerModule, hint, (void *)"state=1"); } else { m_pPowerModule->powerHint(m_pPowerModule, hint, (void *)"state=0"); } } #endif } /*=========================================================================== * FUNCTION : powerHint * * DESCRIPTION: Sets the requested power hint and state to power HAL. * * PARAMETERS : * hint : Power hint * enable : Enable power hint if set to 1. Disable if set to 0. * RETURN : void * *==========================================================================*/ void QCameraPerfLock::powerHint(power_hint_t hint, uint32_t enable) { #ifdef HAS_MULTIMEDIA_HINTS if (mCurrentPowerHintEnable) { //disable previous hint powerHintInternal(mCurrentPowerHint, 0); } powerHintInternal(hint, enable); mCurrentPowerHint = hint; mCurrentPowerHintEnable = enable; #endif } }; // namespace qcamera