1 /* Copyright (c) 2015, 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 #include <cutils/properties.h>
33 #include <stdlib.h>
34 #include <utils/Log.h>
35 #include "QCameraPerf.h"
36 
37 #ifdef CDBG
38 #undef CDBG
39 #endif //#ifdef CDBG
40 #define CDBG(fmt, args...) ALOGD_IF(gCamHalLogLevel >= 2, fmt, ##args)
41 
42 #ifdef CDBG_HIGH
43 #undef CDBG_HIGH
44 #endif //#ifdef CDBG_HIGH
45 #define CDBG_HIGH(fmt, args...) ALOGD_IF(gCamHalLogLevel >= 1, fmt, ##args)
46 
47 
48 namespace qcamera {
49 
50 extern volatile uint32_t gCamHalLogLevel;
51 
52 /*===========================================================================
53  * FUNCTION   : QCameraPerfLock constructor
54  *
55  * DESCRIPTION: initialize member variables
56  *
57  * PARAMETERS :
58  *   None
59  *
60  * RETURN     : void
61  *
62  *==========================================================================*/
QCameraPerfLock()63 QCameraPerfLock::QCameraPerfLock() :
64         perf_lock_acq(NULL),
65         perf_lock_rel(NULL),
66         mDlHandle(NULL),
67         mPerfLockEnable(0),
68         mPerfLockHandle(-1),
69         mPerfLockHandleTimed(-1),
70         mTimerSet(0),
71         mPerfLockTimeout(0),
72         mStartTimeofLock(0)
73 {
74 }
75 
76 /*===========================================================================
77  * FUNCTION   : QCameraPerfLock destructor
78  *
79  * DESCRIPTION: class desctructor
80  *
81  * PARAMETERS :
82  *   None
83  *
84  * RETURN     : void
85  *
86  *==========================================================================*/
~QCameraPerfLock()87 QCameraPerfLock::~QCameraPerfLock()
88 {
89     lock_deinit();
90 }
91 
92 
93 /*===========================================================================
94  * FUNCTION   : lock_init
95  *
96  * DESCRIPTION: opens the performance lib and initilizes the perf lock functions
97  *
98  * PARAMETERS :
99  *   None
100  *
101  * RETURN     : void
102  *
103  *==========================================================================*/
lock_init()104 void QCameraPerfLock::lock_init()
105 {
106     const char *rc;
107     char value[PROPERTY_VALUE_MAX];
108     int len;
109 
110     CDBG("%s E", __func__);
111     Mutex::Autolock lock(mLock);
112 
113     property_get("persist.camera.perflock.enable", value, "1");
114     mPerfLockEnable = atoi(value);
115     mCurrentPowerHintEnable = 0;
116 #ifdef HAS_MULTIMEDIA_HINTS
117     if (hw_get_module(POWER_HARDWARE_MODULE_ID, (const hw_module_t **)&m_pPowerModule)) {
118         ALOGE("%s: %s module not found", __func__, POWER_HARDWARE_MODULE_ID);
119     }
120 #endif
121 
122     if (mPerfLockEnable) {
123         perf_lock_acq = NULL;
124         perf_lock_rel = NULL;
125         mPerfLockHandle = -1;
126         /* Retrieve name of vendor extension library */
127         if (property_get("ro.vendor.extension_library", value, NULL) <= 0) {
128             goto cleanup;
129         }
130 
131         mDlHandle = dlopen(value, RTLD_NOW | RTLD_LOCAL);
132         if (mDlHandle == NULL) {
133             goto cleanup;
134         }
135 
136         dlerror();
137 
138         perf_lock_acq = (int (*) (int, int, int[], int))dlsym(mDlHandle, "perf_lock_acq");
139         if ((rc = dlerror()) != NULL) {
140             ALOGE("%s: failed to perf_lock_acq function handle", __func__);
141             goto cleanup;
142         }
143 
144         perf_lock_rel = (int (*) (int))dlsym(mDlHandle, "perf_lock_rel");
145         if ((rc = dlerror()) != NULL) {
146             ALOGE("%s: failed to perf_lock_rel function handle", __func__);
147             goto cleanup;
148         }
149         CDBG("%s X", __func__);
150         return;
151 
152 cleanup:
153         perf_lock_acq  = NULL;
154         perf_lock_rel  = NULL;
155         mPerfLockEnable = 0;
156         if (mDlHandle) {
157             dlclose(mDlHandle);
158             mDlHandle = NULL;
159         }
160     }
161     CDBG("%s X", __func__);
162 }
163 
164 /*===========================================================================
165  * FUNCTION   : lock_deinit
166  *
167  * DESCRIPTION: deinitialize the perf lock parameters
168  *
169  * PARAMETERS :
170  *   None
171  *
172  * RETURN     : void
173  *
174  *==========================================================================*/
lock_deinit()175 void QCameraPerfLock::lock_deinit()
176 {
177     Mutex::Autolock lock(mLock);
178     if (mPerfLockEnable) {
179         CDBG("%s E", __func__);
180         if (mDlHandle) {
181             perf_lock_acq  = NULL;
182             perf_lock_rel  = NULL;
183 
184             dlclose(mDlHandle);
185             mDlHandle       = NULL;
186         }
187         mPerfLockEnable = 0;
188         CDBG("%s X", __func__);
189     }
190 }
191 
192 /*===========================================================================
193  * FUNCTION   : isTimerReset
194  *
195  * DESCRIPTION: Check if timout duration is reached
196  *
197  * PARAMETERS : None
198  *
199  * RETURN     : true if timeout reached
200  *              false if timeout not reached
201  *
202  *==========================================================================*/
isTimerReset()203 bool QCameraPerfLock::isTimerReset()
204 {
205     Mutex::Autolock lock(mLock);
206     if (mPerfLockEnable && mTimerSet) {
207         nsecs_t timeDiff = systemTime() - mStartTimeofLock;
208         if (ns2ms(timeDiff) > (uint32_t)mPerfLockTimeout) {
209             mTimerSet = 0;
210             return true;
211         }
212     }
213     return false;
214 }
215 
216 /*===========================================================================
217  * FUNCTION   : start_timer
218  *
219  * DESCRIPTION: get the start of the timer
220  *
221  * PARAMETERS :
222  *  @timer_val: timer duration in milliseconds
223  *
224  * RETURN     : int32_t type of status
225  *              NO_ERROR  -- success
226  *              none-zero failure code
227  *
228  *==========================================================================*/
startTimer(uint32_t timer_val)229 void QCameraPerfLock::startTimer(uint32_t timer_val)
230 {
231     mStartTimeofLock = systemTime();
232     mTimerSet = 1;
233     mPerfLockTimeout = timer_val;
234 }
235 
236 /*===========================================================================
237  * FUNCTION   : lock_acq_timed
238  *
239  * DESCRIPTION: Acquire the performance lock for the specified duration.
240  *              If an existing lock timeout has not elapsed, extend the
241  *              lock further for the specified duration
242  *
243  * PARAMETERS :
244  *  @timer_val: lock duration
245  *
246  * RETURN     : int32_t type of status
247  *              NO_ERROR  -- success
248  *              none-zero failure code
249  *
250  *==========================================================================*/
lock_acq_timed(int32_t timer_val)251 int32_t QCameraPerfLock::lock_acq_timed(int32_t timer_val)
252 {
253     int32_t ret = -1;
254 
255     CDBG("%s E", __func__);
256     Mutex::Autolock lock(mLock);
257 
258     if (mPerfLockEnable) {
259         int32_t perf_lock_params[] = {
260                 ALL_CPUS_PWR_CLPS_DIS,
261                 CPU0_MIN_FREQ_TURBO_MAX,
262                 CPU4_MIN_FREQ_TURBO_MAX
263         };
264         if (mTimerSet) {
265             nsecs_t curElapsedTime = systemTime() - mStartTimeofLock;
266             int32_t pendingTimeout = mPerfLockTimeout - ns2ms(curElapsedTime);
267             timer_val += pendingTimeout;
268         }
269         startTimer(timer_val);
270 
271         // Disable power hint when acquiring the perf lock
272         if (mCurrentPowerHintEnable) {
273             CDBG_HIGH("%s mCurrentPowerHintEnable %d", __func__ ,mCurrentPowerHintEnable);
274             powerHintInternal(mCurrentPowerHint, 0);
275         }
276 
277         if ((NULL != perf_lock_acq) && (mPerfLockHandleTimed < 0)) {
278             ret = (*perf_lock_acq)(mPerfLockHandleTimed, timer_val, perf_lock_params,
279                     sizeof(perf_lock_params) / sizeof(int32_t));
280             CDBG("%s ret %d", __func__, ret);
281             if (ret < 0) {
282                 ALOGE("%s: failed to acquire lock", __func__);
283             } else {
284                 mPerfLockHandleTimed = ret;
285             }
286         }
287         CDBG("%s perf_handle_acq %d ",__func__, mPerfLockHandleTimed);
288     }
289 
290     CDBG("%s X", __func__);
291     return ret;
292 }
293 
294 /*===========================================================================
295  * FUNCTION   : lock_acq
296  *
297  * DESCRIPTION: acquire the performance lock
298  *
299  * PARAMETERS :
300  *   None
301  *
302  * RETURN     : int32_t type of status
303  *              NO_ERROR  -- success
304  *              none-zero failure code
305  *
306  *==========================================================================*/
lock_acq()307 int32_t QCameraPerfLock::lock_acq()
308 {
309     int32_t ret = -1;
310 
311     CDBG("%s E", __func__);
312     Mutex::Autolock lock(mLock);
313 
314     if (mPerfLockEnable) {
315         int32_t perf_lock_params[] = {
316                 ALL_CPUS_PWR_CLPS_DIS,
317                 CPU0_MIN_FREQ_TURBO_MAX,
318                 CPU4_MIN_FREQ_TURBO_MAX
319         };
320 
321         // Disable power hint when acquiring the perf lock
322         if (mCurrentPowerHintEnable) {
323             powerHintInternal(mCurrentPowerHint, 0);
324         }
325 
326         if ((NULL != perf_lock_acq) && (mPerfLockHandle < 0)) {
327             ret = (*perf_lock_acq)(mPerfLockHandle, ONE_SEC, perf_lock_params,
328                     sizeof(perf_lock_params) / sizeof(int32_t));
329             CDBG("%s ret %d", __func__, ret);
330             if (ret < 0) {
331                 ALOGE("%s: failed to acquire lock", __func__);
332             } else {
333                 mPerfLockHandle = ret;
334             }
335         }
336         CDBG("%s perf_handle_acq %d ",__func__, mPerfLockHandle);
337     }
338 
339     CDBG("%s X", __func__);
340     return ret;
341 }
342 
343 /*===========================================================================
344  * FUNCTION   : lock_rel_timed
345  *
346  * DESCRIPTION: release the performance lock
347  *
348  * PARAMETERS :
349  *   None
350  *
351  * RETURN     : int32_t type of status
352  *              NO_ERROR  -- success
353  *              none-zero failure code
354  *
355  *==========================================================================*/
lock_rel_timed()356 int32_t QCameraPerfLock::lock_rel_timed()
357 {
358     int ret = -1;
359     Mutex::Autolock lock(mLock);
360     if (mPerfLockEnable) {
361         CDBG("%s E", __func__);
362         if (mPerfLockHandleTimed < 0) {
363             ALOGE("%s: mPerfLockHandle < 0,check if lock is acquired", __func__);
364             return ret;
365         }
366         CDBG("%s perf_handle_rel %d ",__func__, mPerfLockHandleTimed);
367 
368         if ((NULL != perf_lock_rel) && (0 <= mPerfLockHandleTimed)) {
369             ret = (*perf_lock_rel)(mPerfLockHandleTimed);
370             if (ret < 0) {
371                 ALOGE("%s: failed to release lock", __func__);
372             }
373             mPerfLockHandleTimed = -1;
374         }
375 
376         if ((mCurrentPowerHintEnable == 1) && (mTimerSet == 0)) {
377             powerHintInternal(mCurrentPowerHint, mCurrentPowerHintEnable);
378         }
379         CDBG("%s X", __func__);
380     }
381     return ret;
382 }
383 
384 /*===========================================================================
385  * FUNCTION   : lock_rel
386  *
387  * DESCRIPTION: release the performance lock
388  *
389  * PARAMETERS :
390  *   None
391  *
392  * RETURN     : int32_t type of status
393  *              NO_ERROR  -- success
394  *              none-zero failure code
395  *
396  *==========================================================================*/
lock_rel()397 int32_t QCameraPerfLock::lock_rel()
398 {
399     int ret = -1;
400     Mutex::Autolock lock(mLock);
401     if (mPerfLockEnable) {
402         CDBG("%s E", __func__);
403         if (mPerfLockHandle < 0) {
404             ALOGE("%s: mPerfLockHandle < 0,check if lock is acquired", __func__);
405             return ret;
406         }
407         CDBG("%s perf_handle_rel %d ",__func__, mPerfLockHandle);
408 
409         if ((NULL != perf_lock_rel) && (0 <= mPerfLockHandle)) {
410             ret = (*perf_lock_rel)(mPerfLockHandle);
411             if (ret < 0) {
412                 ALOGE("%s: failed to release lock", __func__);
413             }
414             mPerfLockHandle = -1;
415         }
416 
417         if ((mCurrentPowerHintEnable == 1) && (mTimerSet == 0)) {
418             powerHintInternal(mCurrentPowerHint, mCurrentPowerHintEnable);
419         }
420         CDBG("%s X", __func__);
421     }
422     return ret;
423 }
424 
425 /*===========================================================================
426  * FUNCTION   : powerHintInternal
427  *
428  * DESCRIPTION: Sets the requested power hint and state to power HAL.
429  *
430  * PARAMETERS :
431  * enable     : Enable power hint if set to 1. Disable if set to 0.
432  * RETURN     : void
433  *
434  *==========================================================================*/
powerHintInternal(power_hint_t hint,uint32_t enable)435 void QCameraPerfLock::powerHintInternal(power_hint_t hint, uint32_t enable)
436 {
437 #ifdef HAS_MULTIMEDIA_HINTS
438     if (m_pPowerModule != NULL) {
439         if (enable == 1) {
440             m_pPowerModule->powerHint(m_pPowerModule, hint, (void *)"state=1");
441         }
442         else {
443             m_pPowerModule->powerHint(m_pPowerModule, hint, (void *)"state=0");
444         }
445     }
446 #endif
447 }
448 
449 /*===========================================================================
450  * FUNCTION   : powerHint
451  *
452  * DESCRIPTION: Sets the requested power hint and state to power HAL.
453  *
454  * PARAMETERS :
455  * hint       : Power hint
456  * enable     : Enable power hint if set to 1. Disable if set to 0.
457  * RETURN     : void
458  *
459  *==========================================================================*/
powerHint(power_hint_t hint,uint32_t enable)460 void QCameraPerfLock::powerHint(power_hint_t hint, uint32_t enable)
461 {
462 #ifdef HAS_MULTIMEDIA_HINTS
463     if (mCurrentPowerHintEnable) {
464         //disable previous hint
465         powerHintInternal(mCurrentPowerHint, 0);
466     }
467     powerHintInternal(hint, enable);
468 
469     mCurrentPowerHint       = hint;
470     mCurrentPowerHintEnable = enable;
471 #endif
472 }
473 
474 }; // namespace qcamera
475