Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3a188f47 authored by Sooraj S's avatar Sooraj S 👽
Browse files

FP3: Add device specific power class

This is a copy from /hardware/qcom/power/power-8953.c
which is modified to device specific needs
parent 16b143b1
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -201,6 +201,11 @@ NUM_FRAMEBUFFER_SURFACE_BUFFERS := 3
TARGET_USES_MEDIA_EXTENSIONS := true
TARGET_MOUNT_POINTS_SYMLINKS := false

# Power
BOARD_POWER_CUSTOM_BOARD_LIB := libpower_8953
TARGET_HAS_NO_WLAN_STATS := true
TARGET_USES_INTERACTION_BOOST := true

# DRM
TARGET_ENABLE_MEDIADRM_64 := true

+93 −67
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@

<!--
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
 * Copyright (c) 2020, The eOS Project.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -29,71 +30,96 @@
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
-->

<HintConfigs>
    <Powerhint>
    <Hint type="0x0E00"> <!--preview-->
        <Resource opcode="0x41400000" value="0x4"  />   <!-- B CPU - above_hispeed_delay of 40 ms -->
        <Resource opcode="0x41410000" value="0x5F" />   <!-- B CPU - go hispeed load 95 -->
        <Resource opcode="0x41414000" value="0x22C"/>   <!-- B CPU - hispeed freq of 556 MHz -->
        <Resource opcode="0x41420000" value="0x5A" />   <!-- B CPU - target load of 90 -->
        <Resource opcode="0x41400100" value="0x4"  />   <!-- L CPU - above_hispeed_delay of 40 ms -->
        <Resource opcode="0x41410100" value="0x5F" />   <!-- L CPU - go hispeed load 95 -->
        <Resource opcode="0x41414100" value="0x22C"/>   <!-- L CPU - hispeed freq of 556 MHz- -->
        <Resource opcode="0x41420100" value="0x5A" />   <!-- L CPU - target load of 90 -->
        <Resource opcode="0x41810000" value="0x9C4"/>   <!-- CPUBW low power ceil mpbs of 2500 -->
        <Resource opcode="0x41814000" value="0x32" />   <!-- CPUBW low power io percent of 50 -->
    </Hint>
    <Hint type="0x0A00"> <!--video encode 30 fps-->
        <Resource opcode="0x41400000" value="0x4"  />   <!-- B CPU - above_hispeed_delay of 40 ms -->
        <Resource opcode="0x41410000" value="0x5F" />   <!-- B CPU - go hispeed load 95 -->
        <Resource opcode="0x41414000" value="0x326"/>   <!-- B CPU - hispeed freq of 806 MHz -->
        <Resource opcode="0x41420000" value="0x5A" />   <!-- B CPU - target load of 90 -->
        <Resource opcode="0x41400100" value="0x4"  />   <!-- L CPU - above_hispeed_delay of 40 ms -->
        <Resource opcode="0x41410100" value="0x5F" />   <!-- L CPU - go hispeed load 95 -->
        <Resource opcode="0x41414100" value="0x22C"/>   <!-- L CPU - hispeed freq of 556 MHz- -->
        <Resource opcode="0x41420100" value="0x5A" />   <!-- L CPU - target load of 90 -->
        <Resource opcode="0x41810000" value="0x9C4"/>   <!-- CPUBW low power ceil mpbs of 2500 -->
        <Resource opcode="0x41814000" value="0x32" />   <!-- CPUBW low power io percent of 50 -->
        <Resource opcode="0x4180C000" value="0x0"  />   <!-- CPUBW disable hysteresis -->
        <Resource opcode="0x41820000" value="0xA"  />   <!-- CPUBW sample_ms of 10ms -->
        <Resource opcode="0x41438100" value="0x0"  />   <!-- L CPU - disable ignore_hispeed_notif -->
        <Resource opcode="0x41438000" value="0x0"  />   <!-- B CPU - disable ignore_hispeed_notif -->
    </Hint>
    <Hint type="0x0B00"> <!--video decode-->
        <Resource opcode="0x41400100" value="0x4"  />   <!-- L CPU - Above Hispeed Delay of 40ms -->
        <Resource opcode="0x41410100" value="0x5F" />   <!-- L CPU - Go Hispeed Delay of 95 -->
        <Resource opcode="0x41414100" value="0x2D9"/>   <!-- L CPU - Hispeed Freq of 768 MHz -->
        <Resource opcode="0x41420100" value="0x5A" />   <!-- L CPU - Target Loads of 90 -->
        <Resource opcode="0x41400000" value="0x4"  />   <!-- B CPU - Above Hispeed Delay of 40ms -->
        <Resource opcode="0x41410000" value="0x5F" />   <!-- B CPU - Go Hispeed Load of 95 -->
        <Resource opcode="0x41414000" value="0x2D9"/>   <!-- B CPU - Hispeed Freq of 729 MHz -->
        <Resource opcode="0x41420000" value="0x5A" />   <!-- B CPU - Target Load of 90 -->
    </Hint>
	<Hint type="0x0F00"> <!--sustained performance-->
        <Resource opcode="0x40800000" value="0x0"/>     <!-- B CPU - Cluster min freq uncapped -->
        <Resource opcode="0x40800100" value="0x0"/>     <!-- L CPU - Cluster min freq uncapped -->
        <Resource opcode="0x40804000" value="0x4E0"/>   <!-- B CPU - Cluster max freq ~1.2 GHz -->
        <Resource opcode="0x40804100" value="0x4E0"/>   <!-- L CPU - Cluster max freq ~1.2 Ghz -->
        <Resource opcode="0x4280C000" value="0xB4"/>    <!-- GPU - min freq 180 Mhz -->
        <Resource opcode="0x42810000" value="0x156"/>   <!-- GPU - max freq 342 Mhz -->
        <Resource opcode="0x42814000" value="0x0"/>     <!-- GPUBW freq uncapped -->
    </Hint>
	<Hint type="0x1000"> <!--vr mode-->
        <Resource opcode="0x40800000" value="0x579"/>   <!-- B CPU - Cluster min freq ~1.4 Ghz -->
        <Resource opcode="0x40800100" value="0x579"/>   <!-- L CPU - Cluster min freq ~1.4 Ghz -->
        <Resource opcode="0x40804000" value="0x579"/>   <!-- B CPU - Cluster max freq ~1.4 Ghz -->
        <Resource opcode="0x40804100" value="0x579"/>   <!-- L CPU - Cluster max freq ~1.4 Ghz -->
        <Resource opcode="0x4280C000" value="0x203"/>   <!-- GPU - min freq 510 Mhz -->
        <Resource opcode="0x42810000" value="0x203"/>   <!-- GPU - max freq 510 Mhz -->
        <Resource opcode="0x42814000" value="0x1E4F"/>  <!-- GPUBW freq 775 Mhz-->
    </Hint>
	<Hint type="0x1001"> <!--vr mode sustained performance-->
        <Resource opcode="0x40800000" value="0x4E0"/>   <!-- B CPU - Cluster min freq ~1.2 Ghz -->
        <Resource opcode="0x40800100" value="0x4E0"/>   <!-- L CPU - Cluster min freq ~1.2 Ghz -->
        <Resource opcode="0x40804000" value="0x4E0"/>   <!-- B CPU - Cluster max freq ~1.2 Ghz -->
        <Resource opcode="0x40804100" value="0x4E0"/>   <!-- L CPU - Cluster max freq ~1.2 Ghz -->
        <Resource opcode="0x4280C000" value="0x156"/>   <!-- GPU - min freq 342 Mhz -->
        <Resource opcode="0x42810000" value="0x156"/>   <!-- GPU - max freq 342 Mhz -->
        <Resource opcode="0x42814000" value="0x1E4F"/>  <!-- GPUBW freq 775 Mhz -->
    </Hint>
        <!--preview-->
        <!-- B CPU - above_hispeed_delay of 40 ms -->
        <!-- B CPU - go hispeed load 95 -->
        <!-- B CPU - hispeed freq of 556 MHz -->
        <!-- B CPU - target load of 90 -->
        <!-- L CPU - above_hispeed_delay of 40 ms -->
        <!-- L CPU - go hispeed load 95 -->
        <!-- L CPU - hispeed freq of 556 MHz- -->
        <!-- L CPU - target load of 90 -->
        <!-- CPUBW low power ceil mpbs of 2500 -->
        <!-- CPUBW low power io percent of 50 -->
        <Config
            Id="0x00001300" Enable="true" Target="msm8953"
            Resources="0x41400000, 0x4, 0x41410000, 0x5F, 0x41414000, 0x22C, 0x41420000, 0x5A, 0x41400100, 0x4, 0x41410100, 0x5F
            , 0x41414100, 0x22C, 0x41420100, 0x5A, 0x41810000, 0x9C4, 0x41814000, 0x32" />

        <!--video encode 30 fps-->
        <!-- B CPU - above_hispeed_delay of 40 ms -->
        <!-- B CPU - go hispeed load 95 -->
        <!-- B CPU - hispeed freq of 806 MHz -->
        <!-- B CPU - target load of 90 -->
        <!-- L CPU - above_hispeed_delay of 40 ms -->
        <!-- L CPU - go hispeed load 95 -->
        <!-- L CPU - hispeed freq of 556 MHz- -->
        <!-- L CPU - target load of 90 -->
        <!-- CPUBW low power ceil mpbs of 2500 -->
        <!-- CPUBW low power io percent of 50 -->
        <!-- CPUBW disable hysteresis -->
        <!-- CPUBW sample_ms of 10ms -->
        <!-- L CPU - disable ignore_hispeed_notif -->
        <!-- B CPU - disable ignore_hispeed_notif -->
        <Config
            Id="0x00001203" Enable="true" Target="msm8953"
            Resources="0x41400000, 0x4, 0x41410000, 0x5F ,0x41414000, 0x326, 0x41420000, 0x5A, 0x41400100, 0x4, 0x41410100
            , 0x5F, 0x41414100, 0x22C, 0x41420100, 0x5A, 0x41810000 ,0x9C4, 0x41814000,
            0x32, 0x4180C000 ,0x0, 0x41820000, 0xA, 0x41438100, 0x0, 0x41438000, 0x0" />

        <!--video decode-->
        <!-- L CPU - above_hispeed_delay of 40 ms -->
        <!-- L CPU - go hispeed load 95 -->
        <!-- L CPU - hispeed freq of 768 MHz- -->
        <!-- L CPU - target load of 90 -->
        <!-- B CPU - above_hispeed_delay of 40 ms -->
        <!-- B CPU - go hispeed load 95 -->
        <!-- B CPU - hispeed freq of 729 MHz -->
        <!-- B CPU - target load of 90 -->
        <Config
            Id="0x00001204" Enable="true" Target="msm8953"
            Resources="0x41400100, 0x4, 0x41410100, 0x5F ,0x41414100, 0x2D9, 0x41420100, 0x5A, 0x41400000, 0x4, 0x41410000
            , 0x5F, 0x41414000, 0x2D9, 0x41420000, 0x5A" />

        <!--sustained performance-->
        <!-- B CPU - Cluster min freq uncapped -->
        <!-- L CPU - Cluster min freq uncapped -->
        <!-- B CPU - Cluster max freq ~1.2 GHz -->
        <!-- L CPU - Cluster max freq ~1.2 Ghz -->
        <!-- GPU - min freq 180 Mhz -->
        <!-- GPU - max freq 342 Mhz -->
        <!-- GPUBW freq uncapped -->
        <Config
            Id="0x00001206" Enable="true" Target="msm8953"
            Resources="0x40800000, 0x0, 0x40800100, 0x0, 0x40804000, 0x4E0, 0x40804100, 0x4E0,
            0x4280C000, 0xB4, 0x42810000, 0x156, 0x42814000, 0x0"/>

        <!--vr mode-->
        <!-- B CPU - Cluster min freq ~1.4 Ghz -->
        <!-- L CPU - Cluster min freq ~1.4 Ghz -->
        <!-- B CPU - Cluster max freq ~1.4 Ghz -->
        <!-- L CPU - Cluster max freq ~1.4 Ghz -->
        <!-- GPU - min freq 510 Mhz -->
        <!-- GPU - max freq 510 Mhz -->
        <!-- GPUBW freq 775 Mhz-->
        <Config
            Id="0x00001207" Enable="true" Target="msm8953"
            Resources="0x40800000, 0x579, 0x40800100, 0x579, 0x40804000, 0x579, 0x40804100, 0x579,
            0x4280C000, 0x203, 0x42810000, 0x203, 0x42814000, 0x1E4F"/>

        <!--vr mode sustained performance-->
        <!-- B CPU - Cluster min freq ~1.2 Ghz -->
        <!-- L CPU - Cluster min freq ~1.2 Ghz -->
        <!-- B CPU - Cluster max freq ~1.2 Ghz -->
        <!-- L CPU - Cluster max freq ~1.2 Ghz -->
        <!-- GPU - min freq 342 Mhz -->
        <!-- GPU - max freq 342 Mhz -->
        <!-- GPUBW freq 775 Mhz -->
        <Config
            Id="0x00001301" Enable="true" Target="msm8953"
            Resources="0x40800000, 0x4E0, 0x40800100, 0x4E0, 0x40804000, 0x4E0, 0x40804100, 0x4E0, 0x4280C000, 0x156,
            0x42810000, 0x156, 0x42814000, 0x1E4F"/>
    </Powerhint>
</HintConfigs>

power/Android.mk

0 → 100644
+17 −0
Original line number Diff line number Diff line
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_C_INCLUDES := hardware/qcom/power
LOCAL_CFLAGS := -Wall -Werror
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_HEADER_LIBRARIES += libhardware_headers

ifeq ($(TARGET_USES_INTERACTION_BOOST),true)
    LOCAL_CFLAGS += -DINTERACTION_BOOST
endif

LOCAL_SRC_FILES := power-8953.c
LOCAL_MODULE := libpower_8953
LOCAL_VENDOR_MODULE := true
include $(BUILD_STATIC_LIBRARY)

power/power-8953.c

0 → 100644
+408 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2016, The Linux Foundation. All rights reserved.
 * Copyright (C) 2018 The LineageOS Project
 *
 * 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_NIDEBUG 0

#include <errno.h>
#include <time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <stdlib.h>

#define LOG_TAG "QCOM PowerHAL"
#include <log/log.h>
#include <hardware/hardware.h>
#include <hardware/power.h>

#include "utils.h"
#include "metadata-defs.h"
#include "hint-data.h"
#include "performance.h"
#include "power-common.h"

#define NUM_PERF_MODES  3

const int kMaxLaunchDuration = 5000; /* ms */
const int kMaxInteractiveDuration = 5000; /* ms */
const int kMinInteractiveDuration = 500; /* ms */

static int current_power_profile = PROFILE_BALANCED;

static int profile_high_performance[] = {
    SCHED_BOOST_ON_V3, 0x1,
    ALL_CPUS_PWR_CLPS_DIS_V3, 0x1,
    MIN_FREQ_BIG_CORE_0, 0xFFF,
    MIN_FREQ_LITTLE_CORE_0, 0xFFF,
    GPU_MIN_POWER_LEVEL, 0x1,
    SCHED_PREFER_IDLE_DIS_V3, 0x1,
    SCHED_MOSTLY_IDLE_NR_RUN, 0x1,
    SCHED_MOSTLY_IDLE_LOAD, 0x1,
};

static int profile_power_save[] = {
    MAX_FREQ_BIG_CORE_0, 0x3bf,
    MAX_FREQ_LITTLE_CORE_0, 0x300,
};

static int profile_bias_power[] = {
    MAX_FREQ_BIG_CORE_0, 0x4B0,
    MAX_FREQ_LITTLE_CORE_0, 0x300,
};

static int profile_bias_performance[] = {
    MIN_FREQ_BIG_CORE_0, 0x540,
};

#ifdef INTERACTION_BOOST
int get_number_of_profiles()
{
    return 5;
}
#endif

static int set_power_profile(void *data)
{
    int profile = data ? *((int*)data) : 0;
    int ret = -EINVAL;
    const char *profile_name = NULL;

    if (profile == current_power_profile)
        return 0;

    ALOGV("%s: Profile=%d", __func__, profile);

    if (current_power_profile != PROFILE_BALANCED) {
        undo_hint_action(DEFAULT_PROFILE_HINT_ID);
        ALOGV("%s: Hint undone", __func__);
        current_power_profile = PROFILE_BALANCED;
    }

    if (profile == PROFILE_POWER_SAVE) {
        ret = perform_hint_action(DEFAULT_PROFILE_HINT_ID, profile_power_save,
                ARRAY_SIZE(profile_power_save));
        profile_name = "powersave";

    } else if (profile == PROFILE_HIGH_PERFORMANCE) {
        ret = perform_hint_action(DEFAULT_PROFILE_HINT_ID,
                profile_high_performance, ARRAY_SIZE(profile_high_performance));
        profile_name = "performance";

    } else if (profile == PROFILE_BIAS_POWER) {
        ret = perform_hint_action(DEFAULT_PROFILE_HINT_ID, profile_bias_power,
                ARRAY_SIZE(profile_bias_power));
        profile_name = "bias power";

    } else if (profile == PROFILE_BIAS_PERFORMANCE) {
        ret = perform_hint_action(DEFAULT_PROFILE_HINT_ID,
                profile_bias_performance, ARRAY_SIZE(profile_bias_performance));
        profile_name = "bias perf";
    } else if (profile == PROFILE_BALANCED) {
        ret = 0;
        profile_name = "balanced";
    }

    if (ret == 0) {
        current_power_profile = profile;
        ALOGD("%s: Set %s mode", __func__, profile_name);
    }
    return ret;
}

typedef enum {
    NORMAL_MODE       = 0,
    SUSTAINED_MODE    = 1,
    VR_MODE           = 2,
    VR_SUSTAINED_MODE = (SUSTAINED_MODE|VR_MODE),
    INVALID_MODE      = 0xFF
} perf_mode_type_t;

typedef struct perf_mode {
    perf_mode_type_t type;
    int perf_hint_id;
} perf_mode_t;

perf_mode_t perf_modes[NUM_PERF_MODES] = {
    { SUSTAINED_MODE, SUSTAINED_PERF_HINT },
    { VR_MODE, VR_MODE_HINT },
    { VR_SUSTAINED_MODE, VR_MODE_SUSTAINED_PERF_HINT }
};

static int current_mode = NORMAL_MODE;

static inline int get_perfd_hint_id(perf_mode_type_t type) {
    int i;
    for (i = 0; i < NUM_PERF_MODES; i++) {
        if (perf_modes[i].type == type) {
            ALOGD("Hint id is 0x%x for mode 0x%x", perf_modes[i].perf_hint_id, type);
            return perf_modes[i].perf_hint_id;
        }
    }
    ALOGD("Couldn't find the hint for mode 0x%x", type);
    return 0;
}

static int switch_mode(perf_mode_type_t mode) {
    int hint_id = 0;
    static int perfd_mode_handle = -1;

    // release existing mode if any
    if (CHECK_HANDLE(perfd_mode_handle)) {
        ALOGD("Releasing handle 0x%x", perfd_mode_handle);
        release_request(perfd_mode_handle);
        perfd_mode_handle = -1;
    }
    // switch to a perf mode
    hint_id = get_perfd_hint_id(mode);
    if (hint_id != 0) {
        perfd_mode_handle = perf_hint_enable(hint_id, 0);
        if (!CHECK_HANDLE(perfd_mode_handle)) {
            ALOGE("Failed perf_hint_interaction for mode: 0x%x", mode);
            return -1;
        }
        ALOGD("Acquired handle 0x%x", perfd_mode_handle);
    }
    return 0;
}

static int process_perf_hint(void *data, perf_mode_type_t mode) {
    // enable
    if (data) {
        ALOGI("Enable request for mode: 0x%x", mode);
        // check if mode is current mode
        if (current_mode & mode) {
            ALOGD("Mode 0x%x already enabled", mode);
            return HINT_HANDLED;
        }
        // enable requested mode
        if (0 != switch_mode(current_mode | mode)) {
            ALOGE("Couldn't enable mode 0x%x", mode);
            return HINT_NONE;
        }
        current_mode |= mode;
        ALOGI("Current mode is 0x%x", current_mode);
    // disable
    } else {
        ALOGI("Disable request for mode: 0x%x", mode);
        // check if mode is enabled
        if (!(current_mode & mode)) {
            ALOGD("Mode 0x%x already disabled", mode);
            return HINT_HANDLED;
        }
        // disable requested mode
        if (0 != switch_mode(current_mode & ~mode)) {
            ALOGE("Couldn't disable mode 0x%x", mode);
            return HINT_NONE;
        }
        current_mode &= ~mode;
        ALOGI("Current mode is 0x%x", current_mode);
    }

    return HINT_HANDLED;
}

static int process_video_encode_hint(void *metadata)
{
    char governor[80];
    struct video_encode_metadata_t video_encode_metadata;
    static int video_encode_handle = 0;

    if (!metadata) {
        return HINT_NONE;
    }

    if (get_scaling_governor_check_cores(governor, sizeof(governor), CPU0) == -1) {
        if (get_scaling_governor_check_cores(governor, sizeof(governor), CPU1) == -1) {
            if (get_scaling_governor_check_cores(governor, sizeof(governor), CPU2) == -1) {
                if (get_scaling_governor_check_cores(governor, sizeof(governor), CPU3) == -1) {
                    ALOGE("Can't obtain scaling governor.");
                    return HINT_NONE;
                }
            }
        }
    }

    /* Initialize encode metadata struct fields */
    memset(&video_encode_metadata, 0, sizeof(struct video_encode_metadata_t));
    video_encode_metadata.state = -1;

    if (parse_video_encode_metadata((char *)metadata, &video_encode_metadata) == -1) {
        ALOGE("Error occurred while parsing metadata.");
        return HINT_NONE;
    }

    if (video_encode_metadata.state == 1) {
        if (is_interactive_governor(governor)) {
            video_encode_handle = perf_hint_enable(
                    VIDEO_ENCODE_HINT, 0);
            return HINT_HANDLED;
        }
    } else if (video_encode_metadata.state == 0) {
        if (is_interactive_governor(governor)) {
            release_request(video_encode_handle);
            return HINT_HANDLED;
        }
    }
    return HINT_NONE;
}

static int process_activity_launch_hint(void *data)
{
    static int launch_handle = -1;
    static int launch_mode = 0;
    // release lock early if launch has finished
    if (!data) {
        if (CHECK_HANDLE(launch_handle)) {
            release_request(launch_handle);
            launch_handle = -1;
        }
        launch_mode = 0;
        return HINT_HANDLED;
    }
    if (current_mode != NORMAL_MODE) {
        ALOGV("%s: ignoring due to other active perf hints", __func__);
    } else if (!launch_mode) {
        launch_handle = perf_hint_enable_with_type(VENDOR_HINT_FIRST_LAUNCH_BOOST,
                kMaxLaunchDuration, LAUNCH_BOOST_V1);
        if (!CHECK_HANDLE(launch_handle)) {
            ALOGE("Failed to perform launch boost");
            return HINT_NONE;
        }
        launch_mode = 1;
    }
    return HINT_HANDLED;
}

static int process_interaction_hint(void *data)
{
    static struct timespec s_previous_boost_timespec;
    static int s_previous_duration = 0;
    struct timespec cur_boost_timespec;
    long long elapsed_time;
    int duration = kMinInteractiveDuration;
    if (current_mode != NORMAL_MODE) {
        ALOGV("%s: ignoring due to other active perf hints", __func__);
        return HINT_HANDLED;
    }
    if (data) {
        int input_duration = *((int*)data);
        if (input_duration > duration) {
            duration = (input_duration > kMaxInteractiveDuration) ?
                    kMaxInteractiveDuration : input_duration;
        }
    }
    clock_gettime(CLOCK_MONOTONIC, &cur_boost_timespec);
    elapsed_time = calc_timespan_us(s_previous_boost_timespec, cur_boost_timespec);
    // don't hint if previous hint's duration covers this hint's duration
    if ((s_previous_duration * 1000) > (elapsed_time + duration * 1000)) {
        return HINT_HANDLED;
    }
    s_previous_boost_timespec = cur_boost_timespec;
    s_previous_duration = duration;

    perf_hint_enable_with_type(VENDOR_HINT_SCROLL_BOOST, duration, SCROLL_VERTICAL);

    return HINT_HANDLED;
}

int power_hint_override(power_hint_t hint, void *data)
{
    int ret_val = HINT_NONE;

    if (hint == POWER_HINT_SET_PROFILE) {
        if (set_power_profile(data) < 0)
            ALOGE("Setting power profile failed. perf HAL not started?");
        return HINT_HANDLED;
    }

    // Skip other hints in high/low power modes
    if (current_power_profile == PROFILE_POWER_SAVE ||
            current_power_profile == PROFILE_HIGH_PERFORMANCE) {
        return HINT_HANDLED;
    }

    switch (hint) {
        case POWER_HINT_VSYNC:
            break;
        case POWER_HINT_VIDEO_ENCODE:
            ret_val = process_video_encode_hint(data);
            break;
        case POWER_HINT_SUSTAINED_PERFORMANCE:
            ret_val = process_perf_hint(data, SUSTAINED_MODE);
            break;
        case POWER_HINT_VR_MODE:
            ret_val = process_perf_hint(data, VR_MODE);
            break;
        case POWER_HINT_INTERACTION:
            ret_val = process_interaction_hint(data);
            break;
        case POWER_HINT_LAUNCH:
            ret_val = process_activity_launch_hint(data);
            break;
        default:
            break;
    }
    return ret_val;
}

int set_interactive_override(int on)
{
    char governor[80];

    if (get_scaling_governor_check_cores(governor, sizeof(governor), CPU0) == -1) {
        if (get_scaling_governor_check_cores(governor, sizeof(governor), CPU1) == -1) {
            if (get_scaling_governor_check_cores(governor, sizeof(governor), CPU2) == -1) {
                if (get_scaling_governor_check_cores(governor, sizeof(governor), CPU3) == -1) {
                    ALOGE("Can't obtain scaling governor.");
                    return HINT_NONE;
                }
            }
        }
    }

    if (!on) {
        /* Display off. */
        if (is_interactive_governor(governor)) {
            int resource_values[] = {
                INT_OP_CLUSTER0_TIMER_RATE, BIG_LITTLE_TR_MS_40
            };
            perform_hint_action(DISPLAY_STATE_HINT_ID,
                    resource_values, ARRAY_SIZE(resource_values));
        }
    } else {
        /* Display on. */
        if (is_interactive_governor(governor)) {
            undo_hint_action(DISPLAY_STATE_HINT_ID);
        }
    }
    return HINT_HANDLED;
}