/* 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