diff --git a/gts3l.mk b/gts3l.mk
index dc23371..ca7c42a 100755
--- a/gts3l.mk
+++ b/gts3l.mk
@@ -288,7 +288,7 @@ PRODUCT_PACKAGES += \
# Power
PRODUCT_PACKAGES += \
- android.hardware.power-service-qti \
+ android.hardware.power@1.1-service.gts3l \
vendor.qti.hardware.perf@1.0
PRODUCT_COPY_FILES += \
diff --git a/manifest.xml b/manifest.xml
index 2e51aab..8709af2 100644
--- a/manifest.xml
+++ b/manifest.xml
@@ -164,6 +164,15 @@
default
+
+ android.hardware.power
+ hwbinder
+ 1.1
+
+ IPower
+ default
+
+
android.hardware.renderscript
passthrough
diff --git a/power/Android.bp b/power/Android.bp
new file mode 100644
index 0000000..1de9635
--- /dev/null
+++ b/power/Android.bp
@@ -0,0 +1,46 @@
+// Copyright (C) 2017 The Android Open Source Project
+// Copyright (C) 2018 The LineageOS Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_binary {
+
+ relative_install_path: "hw",
+ proprietary: true,
+ owner: "qcom",
+
+ name: "android.hardware.power@1.1-service.gts3l",
+ init_rc: ["android.hardware.power@1.1-service.gts3l.rc"],
+ srcs: [
+ "service.cpp",
+ "Power.cpp",
+ "power-helper.c",
+ "metadata-parser.c",
+ "utils.c",
+ "list.c",
+ "hint-data.c",
+ "power-8996.c"
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ "android.hardware.power@1.1",
+ ],
+
+ header_libs: ["libhardware_headers"],
+
+}
diff --git a/power/Power.cpp b/power/Power.cpp
new file mode 100644
index 0000000..74af4a9
--- /dev/null
+++ b/power/Power.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.power@1.1-service.gts3l"
+
+#include
+#include
+
+#include
+
+#include "Power.h"
+#include "power-helper.h"
+
+/* RPM runs at 19.2Mhz. Divide by 19200 for msec */
+#define RPM_CLK 19200
+
+extern struct stat_pair rpm_stat_map[];
+
+namespace android {
+namespace hardware {
+namespace power {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::power::V1_0::Feature;
+using ::android::hardware::power::V1_0::PowerHint;
+using ::android::hardware::power::V1_0::PowerStatePlatformSleepState;
+using ::android::hardware::power::V1_0::Status;
+using ::android::hardware::power::V1_1::PowerStateSubsystem;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+Power::Power() {
+ power_init();
+}
+
+// Methods from ::android::hardware::power::V1_0::IPower follow.
+Return Power::setInteractive(bool interactive) {
+ power_set_interactive(interactive ? 1 : 0);
+ return Void();
+}
+
+Return Power::powerHint(PowerHint hint, int32_t data) {
+ if (android::base::GetProperty("init.svc.vendor.perfd", "") != "running") {
+ ALOGW("perfd is not started");
+ return Void();
+ }
+ power_hint(static_cast(hint), data ? (&data) : NULL);
+ return Void();
+}
+
+Return Power::setFeature(Feature /*feature*/, bool /*activate*/) {
+ return Void();
+}
+
+Return Power::getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) {
+
+ hidl_vec states;
+ uint64_t stats[platform_param_id::PLATFORM_PARAM_COUNT] = {0};
+ struct PowerStatePlatformSleepState *state;
+ int ret;
+
+ ret = extract_platform_stats(stats);
+ if (ret != 0) {
+ states.resize(0);
+ goto done;
+ }
+
+ states.resize(platform_mode_id::RPM_MODE_COUNT);
+
+ /* Update statistics for XO_shutdown */
+ state = &states[platform_mode_id::RPM_MODE_XO];
+ state->name = "XO_shutdown";
+
+ state->residencyInMsecSinceBoot = stats[platform_param_id::ACCUMULATED_VLOW_TIME];
+ state->totalTransitions = stats[platform_param_id::VLOW_COUNT];
+ state->supportedOnlyInSuspend = false;
+ state->voters.resize(XO_VOTERS);
+
+ /* Update statistics for APSS voter */
+ state->voters[0].name = "APSS";
+ state->voters[0].totalTimeInMsecVotedForSinceBoot =
+ stats[platform_param_id::XO_ACCUMULATED_DURATION_APSS] / RPM_CLK;
+ state->voters[0].totalNumberOfTimesVotedSinceBoot = stats[platform_param_id::XO_COUNT_APSS];
+
+ /* Update statistics for MPSS voter */
+ state->voters[1].name = "MPSS";
+ state->voters[1].totalTimeInMsecVotedForSinceBoot =
+ stats[platform_param_id::XO_ACCUMULATED_DURATION_MPSS] / RPM_CLK;
+ state->voters[1].totalNumberOfTimesVotedSinceBoot = stats[platform_param_id::XO_COUNT_MPSS];
+
+ /* Update statistics for ADSP voter */
+ state->voters[2].name = "ADSP";
+ state->voters[2].totalTimeInMsecVotedForSinceBoot =
+ stats[platform_param_id::XO_ACCUMULATED_DURATION_ADSP] / RPM_CLK;
+ state->voters[2].totalNumberOfTimesVotedSinceBoot = stats[platform_param_id::XO_COUNT_ADSP];
+
+ /* Update statistics for SLPI voter */
+ state->voters[3].name = "SLPI";
+ state->voters[3].totalTimeInMsecVotedForSinceBoot =
+ stats[platform_param_id::XO_ACCUMULATED_DURATION_SLPI] / RPM_CLK;
+ state->voters[3].totalNumberOfTimesVotedSinceBoot = stats[platform_param_id::XO_COUNT_SLPI];
+
+
+ /* Update statistics for VMIN state */
+ state = &states[platform_mode_id::RPM_MODE_VMIN];
+ state->name = "VMIN";
+
+ state->residencyInMsecSinceBoot = stats[platform_param_id::ACCUMULATED_VMIN_TIME];
+ state->totalTransitions = stats[platform_param_id::VMIN_COUNT];
+ state->supportedOnlyInSuspend = false;
+ state->voters.resize(VMIN_VOTERS);
+ //Note: No filling of state voters since VMIN_VOTERS = 0
+
+done:
+ _hidl_cb(states, Status::SUCCESS);
+ return Void();
+}
+
+
+// Methods from ::android::hardware::power::V1_1::IPower follow.
+
+Return Power::getSubsystemLowPowerStats(getSubsystemLowPowerStats_cb _hidl_cb) {
+
+ hidl_vec subsystems;
+ int ret;
+
+done:
+ _hidl_cb(subsystems, Status::SUCCESS);
+ return Void();
+}
+
+Return Power::powerHintAsync(PowerHint hint, int32_t data) {
+ // just call the normal power hint in this oneway function
+ return powerHint(hint, data);
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace power
+} // namespace hardware
+} // namespace android
diff --git a/power/Power.h b/power/Power.h
new file mode 100644
index 0000000..2676b7d
--- /dev/null
+++ b/power/Power.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_POWER_V1_1_POWER_H
+#define ANDROID_HARDWARE_POWER_V1_1_POWER_H
+
+#include
+#include
+#include
+#include
+
+namespace android {
+namespace hardware {
+namespace power {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::power::V1_0::Feature;
+using ::android::hardware::power::V1_0::PowerHint;
+using ::android::hardware::power::V1_1::IPower;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct Power : public IPower {
+ // Methods from ::android::hardware::power::V1_0::IPower follow.
+
+ Power();
+
+ Return setInteractive(bool interactive) override;
+ Return powerHint(PowerHint hint, int32_t data) override;
+ Return setFeature(Feature feature, bool activate) override;
+ Return getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) override;
+
+ // Methods from ::android::hardware::power::V1_1::IPower follow.
+ Return getSubsystemLowPowerStats(getSubsystemLowPowerStats_cb _hidl_cb) override;
+ Return powerHintAsync(PowerHint hint, int32_t data) override;
+
+ // Methods from ::android::hidl::base::V1_0::IBase follow.
+
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace power
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_POWER_V1_1_POWER_H
diff --git a/power/android.hardware.power@1.1-service.gts3l.rc b/power/android.hardware.power@1.1-service.gts3l.rc
new file mode 100644
index 0000000..145d285
--- /dev/null
+++ b/power/android.hardware.power@1.1-service.gts3l.rc
@@ -0,0 +1,4 @@
+service vendor.power-hal-1-1 /vendor/bin/hw/android.hardware.power@1.1-service.gts3l
+ class hal
+ user system
+ group system
diff --git a/power/hint-data.c b/power/hint-data.c
new file mode 100644
index 0000000..67da77a
--- /dev/null
+++ b/power/hint-data.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+
+#include "hint-data.h"
+
+int hint_compare(struct hint_data *first_hint,
+ struct hint_data *other_hint) {
+ if (first_hint == other_hint) {
+ return 0;
+ } else if ((first_hint && other_hint) &&
+ (first_hint->hint_id == other_hint->hint_id)) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+void hint_dump(struct hint_data *hint)
+{
+ /*ALOGI("hint_id: %lu", hint->hint_id);*/
+}
diff --git a/power/hint-data.h b/power/hint-data.h
new file mode 100644
index 0000000..9564843
--- /dev/null
+++ b/power/hint-data.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+
+/* Default use-case hint IDs */
+#define DEFAULT_VIDEO_ENCODE_HINT_ID (0x0A00)
+#define DEFAULT_VIDEO_DECODE_HINT_ID (0x0B00)
+#define DISPLAY_STATE_HINT_ID (0x0C00)
+#define DISPLAY_STATE_HINT_ID_2 (0x0D00)
+#define CAM_PREVIEW_HINT_ID (0x0E00)
+
+struct hint_data {
+ unsigned long hint_id; /* This is our key. */
+ unsigned long perflock_handle;
+};
+
+int hint_compare(struct hint_data *first_hint,
+ struct hint_data *other_hint);
+void hint_dump(struct hint_data *hint);
diff --git a/power/list.c b/power/list.c
new file mode 100644
index 0000000..0fe8de2
--- /dev/null
+++ b/power/list.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+
+#include
+#include
+#include
+
+#include "list.h"
+#include
+
+int init_list_head(struct list_node *head)
+{
+ if (head == NULL)
+ return -1;
+
+ memset(head, 0, sizeof(*head));
+
+ return 0;
+}
+
+struct list_node *add_list_node(struct list_node *head, void *data)
+{
+ /* Create a new list_node. And put 'data' into it. */
+ struct list_node *new_node;
+
+ if (head == NULL) {
+ return NULL;
+ }
+
+ if (!(new_node = malloc(sizeof(struct list_node)))) {
+ return NULL;
+ }
+
+ new_node->data = data;
+ new_node->next = head->next;
+ new_node->compare = head->compare;
+ new_node->dump = head->dump;
+ head->next = new_node;
+
+ return new_node;
+}
+
+int is_list_empty(struct list_node *head)
+{
+ return (head == NULL || head->next == NULL);
+}
+
+/*
+ * Delink and de-allocate 'node'.
+ */
+int remove_list_node(struct list_node *head, struct list_node *del_node)
+{
+ struct list_node *current_node;
+ struct list_node *saved_node;
+
+ if (head == NULL || head->next == NULL) {
+ return -1;
+ }
+
+ current_node = head->next;
+ saved_node = head;
+
+ while (current_node && current_node != del_node) {
+ saved_node = current_node;
+ current_node = current_node->next;
+ }
+
+ if (saved_node) {
+ if (current_node) {
+ saved_node->next = current_node->next;
+ } else {
+ /* Node not found. */
+ return -1;
+ }
+ }
+
+ if (del_node) {
+ free(del_node);
+ }
+
+ return 0;
+}
+
+void dump_list(struct list_node *head)
+{
+ struct list_node *current_node = head;
+
+ if (head == NULL)
+ return;
+
+ printf("List:\n");
+
+ while ((current_node = current_node->next)) {
+ if (current_node->dump) {
+ current_node->dump(current_node->data);
+ }
+ }
+}
+
+struct list_node *find_node(struct list_node *head, void *comparison_data)
+{
+ struct list_node *current_node = head;
+
+ if (head == NULL)
+ return NULL;
+
+ while ((current_node = current_node->next)) {
+ if (current_node->compare) {
+ if (current_node->compare(current_node->data,
+ comparison_data) == 0) {
+ /* Match found. Return current_node. */
+ return current_node;
+ }
+ }
+ }
+
+ /* No match found. */
+ return NULL;
+}
diff --git a/power/list.h b/power/list.h
new file mode 100644
index 0000000..d68c3df
--- /dev/null
+++ b/power/list.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+
+struct list_node {
+ struct list_node *next;
+ void *data;
+ int (*compare)(void *data1, void *data2);
+ void (*dump)(void *data);
+};
+
+int init_list_head(struct list_node *head);
+struct list_node * add_list_node(struct list_node *head, void *data);
+int remove_list_node(struct list_node *head, struct list_node *del_node);
+void dump_list(struct list_node *head);
+struct list_node *find_node(struct list_node *head, void *comparison_data);
diff --git a/power/metadata-defs.h b/power/metadata-defs.h
new file mode 100644
index 0000000..5567846
--- /dev/null
+++ b/power/metadata-defs.h
@@ -0,0 +1,62 @@
+/* Copyright (c) 2012, 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 ATTRIBUTE_VALUE_DELIM ('=')
+#define ATTRIBUTE_STRING_DELIM (";")
+
+#define METADATA_PARSING_ERR (-1)
+#define METADATA_PARSING_CONTINUE (0)
+#define METADATA_PARSING_DONE (1)
+
+#define MIN(x,y) (((x)>(y))?(y):(x))
+
+struct video_encode_metadata_t {
+ int hint_id;
+ int state;
+};
+
+struct video_decode_metadata_t {
+ int hint_id;
+ int state;
+};
+
+struct cam_preview_metadata_t {
+ int hint_id;
+ int state;
+};
+
+int parse_metadata(char *metadata, char **metadata_saveptr,
+ char *attribute, unsigned int attribute_size,
+ char *value, unsigned int value_size);
+int parse_video_encode_metadata(char *metadata,
+ struct video_encode_metadata_t *video_encode_metadata);
+int parse_video_decode_metadata(char *metadata,
+ struct video_decode_metadata_t *video_decode_metadata);
+int parse_cam_preview_metadata(char *metadata,
+ struct cam_preview_metadata_t *video_decode_metadata);
diff --git a/power/metadata-parser.c b/power/metadata-parser.c
new file mode 100644
index 0000000..a303069
--- /dev/null
+++ b/power/metadata-parser.c
@@ -0,0 +1,158 @@
+/* Copyright (c) 2012, 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.
+ *
+ */
+
+#include
+#include
+#include
+
+#include "metadata-defs.h"
+
+int parse_metadata(char *metadata, char **metadata_saveptr,
+ char *attribute, unsigned int attribute_size, char *value, unsigned int value_size)
+{
+ char *attribute_string;
+ char *attribute_value_delim;
+ unsigned int bytes_to_copy;
+
+ attribute_string = strtok_r(metadata, ATTRIBUTE_STRING_DELIM,
+ metadata_saveptr);
+
+ if (attribute_string == NULL)
+ return METADATA_PARSING_DONE;
+
+ attribute[0] = value[0] = '\0';
+
+ if ((attribute_value_delim = strchr(attribute_string,
+ ATTRIBUTE_VALUE_DELIM)) != NULL) {
+ unsigned int attribute_len = (unsigned int) (attribute_value_delim - attribute_string);
+ /* copy only attribute len + NUL character, or as much as can be fit */
+ bytes_to_copy = MIN(attribute_len + 1, attribute_size);
+
+ strlcpy(attribute, attribute_string, bytes_to_copy);
+ strlcpy(value, attribute_value_delim + 1, value_size);
+ }
+
+ return METADATA_PARSING_CONTINUE;
+}
+
+int parse_cam_preview_metadata(char *metadata,
+ struct cam_preview_metadata_t *cam_preview_metadata)
+{
+ char attribute[1024], value[1024], *saveptr;
+ char *temp_metadata = metadata;
+ int parsing_status;
+
+ while ((parsing_status = parse_metadata(temp_metadata, &saveptr,
+ attribute, sizeof(attribute), value, sizeof(value))) == METADATA_PARSING_CONTINUE) {
+ if (strlen(attribute) == strlen("hint_id") &&
+ (strncmp(attribute, "hint_id", strlen("hint_id")) == 0)) {
+ if (strlen(value) > 0) {
+ cam_preview_metadata->hint_id = atoi(value);
+ }
+ }
+
+ if (strlen(attribute) == strlen("state") &&
+ (strncmp(attribute, "state", strlen("state")) == 0)) {
+ if (strlen(value) > 0) {
+ cam_preview_metadata->state = atoi(value);
+ }
+ }
+
+ temp_metadata = NULL;
+ }
+
+ if (parsing_status == METADATA_PARSING_ERR)
+ return -1;
+
+ return 0;
+}
+
+int parse_video_encode_metadata(char *metadata,
+ struct video_encode_metadata_t *video_encode_metadata)
+{
+ char attribute[1024], value[1024], *saveptr;
+ char *temp_metadata = metadata;
+ int parsing_status;
+
+ while ((parsing_status = parse_metadata(temp_metadata, &saveptr,
+ attribute, sizeof(attribute), value, sizeof(value))) == METADATA_PARSING_CONTINUE) {
+ if (strlen(attribute) == strlen("hint_id") &&
+ (strncmp(attribute, "hint_id", strlen("hint_id")) == 0)) {
+ if (strlen(value) > 0) {
+ video_encode_metadata->hint_id = atoi(value);
+ }
+ }
+
+ if (strlen(attribute) == strlen("state") &&
+ (strncmp(attribute, "state", strlen("state")) == 0)) {
+ if (strlen(value) > 0) {
+ video_encode_metadata->state = atoi(value);
+ }
+ }
+
+ temp_metadata = NULL;
+ }
+
+ if (parsing_status == METADATA_PARSING_ERR)
+ return -1;
+
+ return 0;
+}
+
+int parse_video_decode_metadata(char *metadata,
+ struct video_decode_metadata_t *video_decode_metadata)
+{
+ char attribute[1024], value[1024], *saveptr;
+ char *temp_metadata = metadata;
+ int parsing_status;
+
+ while ((parsing_status = parse_metadata(temp_metadata, &saveptr,
+ attribute, sizeof(attribute), value, sizeof(value))) == METADATA_PARSING_CONTINUE) {
+ if (strlen(attribute) == strlen("hint_id") &&
+ (strncmp(attribute, "hint_id", strlen("hint_id")) == 0)) {
+ if (strlen(value) > 0) {
+ video_decode_metadata->hint_id = atoi(value);
+ }
+ }
+
+ if (strlen(attribute) == strlen("state") &&
+ (strncmp(attribute, "state", strlen("state")) == 0)) {
+ if (strlen(value) > 0) {
+ video_decode_metadata->state = atoi(value);
+ }
+ }
+
+ temp_metadata = NULL;
+ }
+
+ if (parsing_status == METADATA_PARSING_ERR)
+ return -1;
+
+ return 0;
+}
diff --git a/power/performance.h b/power/performance.h
new file mode 100644
index 0000000..b6db637
--- /dev/null
+++ b/power/performance.h
@@ -0,0 +1,244 @@
+/* Copyright (c) 2012, 2014, 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.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define FAILED -1
+#define SUCCESS 0
+#define INDEFINITE_DURATION 0
+
+enum SCREEN_DISPLAY_TYPE {
+ DISPLAY_OFF = 0x00FF,
+};
+
+enum PWR_CLSP_TYPE {
+ ALL_CPUS_PWR_CLPS_DIS = 0x101,
+};
+
+/* For CPUx min freq, the leftmost byte
+ * represents the CPU and the
+ * rightmost byte represents the frequency
+ * All intermediate frequencies on the
+ * device are supported. The hex value
+ * passed into PerfLock will be multiplied
+ * by 10^5. This frequency or the next
+ * highest frequency available will be set
+ *
+ * For example, if 1.4 Ghz is required on
+ * CPU0, use 0x20E
+ *
+ * If the highest available frequency
+ * on the device is required, use
+ * CPUx_MIN_FREQ_TURBO_MAX
+ * where x represents the CPU
+ */
+enum CPU0_MIN_FREQ_LVL {
+ CPU0_MIN_FREQ_NONTURBO_MAX = 0x20A,
+ CPU0_MIN_FREQ_TURBO_MAX = 0x2FE,
+};
+
+enum CPU1_MIN_FREQ_LVL {
+ CPU1_MIN_FREQ_NONTURBO_MAX = 0x30A,
+ CPU1_MIN_FREQ_TURBO_MAX = 0x3FE,
+};
+
+enum CPU2_MIN_FREQ_LVL {
+ CPU2_MIN_FREQ_NONTURBO_MAX = 0x40A,
+ CPU2_MIN_FREQ_TURBO_MAX = 0x4FE,
+};
+
+enum CPU3_MIN_FREQ_LVL {
+ CPU3_MIN_FREQ_NONTURBO_MAX = 0x50A,
+ CPU3_MIN_FREQ_TURBO_MAX = 0x5FE,
+};
+
+enum CPU0_MAX_FREQ_LVL {
+ CPU0_MAX_FREQ_NONTURBO_MAX = 0x150A,
+};
+
+enum CPU1_MAX_FREQ_LVL {
+ CPU1_MAX_FREQ_NONTURBO_MAX = 0x160A,
+};
+
+enum CPU2_MAX_FREQ_LVL {
+ CPU2_MAX_FREQ_NONTURBO_MAX = 0x170A,
+};
+
+enum CPU3_MAX_FREQ_LVL {
+ CPU3_MAX_FREQ_NONTURBO_MAX = 0x180A,
+};
+
+enum MIN_CPUS_ONLINE_LVL {
+ CPUS_ONLINE_MIN_2 = 0x702,
+ CPUS_ONLINE_MIN_3 = 0x703,
+ CPUS_ONLINE_MIN_4 = 0x704,
+ CPUS_ONLINE_MPD_OVERRIDE = 0x777,
+ CPUS_ONLINE_MAX = 0x7FF,
+};
+
+enum MAX_CPUS_ONLINE_LVL {
+ CPUS_ONLINE_MAX_LIMIT_1 = 0x8FE,
+ CPUS_ONLINE_MAX_LIMIT_2 = 0x8FD,
+ CPUS_ONLINE_MAX_LIMIT_3 = 0x8FC,
+ CPUS_ONLINE_MAX_LIMIT_4 = 0x8FB,
+ CPUS_ONLINE_MAX_LIMIT_MAX = 0x8FB,
+};
+
+enum SAMPLING_RATE_LVL {
+ MS_500 = 0xBCD,
+ MS_50 = 0xBFA,
+ MS_20 = 0xBFD,
+};
+
+enum ONDEMAND_IO_BUSY_LVL {
+ IO_BUSY_OFF = 0xC00,
+ IO_BUSY_ON = 0xC01,
+};
+
+enum ONDEMAND_SAMPLING_DOWN_FACTOR_LVL {
+ SAMPLING_DOWN_FACTOR_1 = 0xD01,
+ SAMPLING_DOWN_FACTOR_4 = 0xD04,
+};
+
+enum INTERACTIVE_TIMER_RATE_LVL {
+ TR_MS_500 = 0xECD,
+ TR_MS_100 = 0xEF5,
+ TR_MS_50 = 0xEFA,
+ TR_MS_30 = 0xEFC,
+ TR_MS_20 = 0xEFD,
+};
+
+/* This timer rate applicable to cpu0
+ across 8939/8952 series chipset */
+enum INTERACTIVE_TIMER_RATE_LVL_CPU0_8939 {
+ TR_MS_CPU0_500 = 0x30CD,
+ TR_MS_CPU0_100 = 0x30F5,
+ TR_MS_CPU0_50 = 0x30FA,
+ TR_MS_CPU0_30 = 0x30FC,
+ TR_MS_CPU0_20 = 0x30FD,
+};
+
+/* This timer rate applicable to cpu4
+ across 8939/8952 series chipset */
+enum INTERACTIVE_TIMER_RATE_LVL_CPU4_8939 {
+ TR_MS_CPU4_500 = 0x3BCD,
+ TR_MS_CPU4_100 = 0x3BF5,
+ TR_MS_CPU4_50 = 0x3BFA,
+ TR_MS_CPU4_30 = 0x3BFC,
+ TR_MS_CPU4_20 = 0x3BFD,
+};
+
+enum INTERACTIVE_HISPEED_FREQ_LVL {
+ HS_FREQ_1026 = 0xF0A,
+};
+
+enum INTERACTIVE_HISPEED_LOAD_LVL {
+ HISPEED_LOAD_90 = 0x105A,
+};
+
+enum SYNC_FREQ_LVL {
+ SYNC_FREQ_300 = 0x1103,
+ SYNC_FREQ_600 = 0X1106,
+ SYNC_FREQ_384 = 0x1103,
+ SYNC_FREQ_NONTURBO_MAX = 0x110A,
+ SYNC_FREQ_TURBO = 0x110F,
+};
+
+enum OPTIMAL_FREQ_LVL {
+ OPTIMAL_FREQ_300 = 0x1203,
+ OPTIMAL_FREQ_600 = 0x1206,
+ OPTIMAL_FREQ_384 = 0x1203,
+ OPTIMAL_FREQ_NONTURBO_MAX = 0x120A,
+ OPTIMAL_FREQ_TURBO = 0x120F,
+};
+
+enum SCREEN_PWR_CLPS_LVL {
+ PWR_CLPS_DIS = 0x1300,
+ PWR_CLPS_ENA = 0x1301,
+};
+
+enum THREAD_MIGRATION_LVL {
+ THREAD_MIGRATION_SYNC_OFF = 0x1400,
+};
+
+enum SCHED_GUIDED_LVL {
+ INTERACTIVE_USE_SCHED_LOAD_OFF = 0x5201,
+ INTERACTIVE_USE_MIGRATION_NOTIF_OFF = 0x5301
+};
+
+enum INTERACTIVE_IO_BUSY_LVL {
+ INTERACTIVE_IO_BUSY_OFF = 0x1B00,
+ INTERACTIVE_IO_BUSY_ON = 0x1B01,
+};
+
+enum SCHED_BOOST_LVL {
+ SCHED_BOOST_ON = 0x1E01,
+};
+
+enum CPU4_MIN_FREQ_LVL {
+ CPU4_MIN_FREQ_NONTURBO_MAX = 0x1F0A,
+ CPU4_MIN_FREQ_TURBO_MAX = 0x1FFE,
+};
+
+enum CPU5_MIN_FREQ_LVL {
+ CPU5_MIN_FREQ_NONTURBO_MAX = 0x200A,
+ CPU5_MIN_FREQ_TURBO_MAX = 0x20FE,
+};
+
+enum CPU6_MIN_FREQ_LVL {
+ CPU6_MIN_FREQ_NONTURBO_MAX = 0x210A,
+ CPU6_MIN_FREQ_TURBO_MAX = 0x21FE,
+};
+
+enum CPU7_MIN_FREQ_LVL {
+ CPU7_MIN_FREQ_NONTURBO_MAX = 0x220A,
+ CPU7_MIN_FREQ_TURBO_MAX = 0x22FE,
+};
+
+enum CPU4_MAX_FREQ_LVL {
+ CPU4_MAX_FREQ_NONTURBO_MAX = 0x230A,
+};
+
+enum CPU5_MAX_FREQ_LVL {
+ CPU5_MAX_FREQ_NONTURBO_MAX = 0x240A,
+};
+
+enum CPU6_MAX_FREQ_LVL {
+ CPU6_MAX_FREQ_NONTURBO_MAX = 0x250A,
+};
+
+enum CPU7_MAX_FREQ_LVL {
+ CPU7_MAX_FREQ_NONTURBO_MAX = 0x260A,
+};
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/power/power-8996.c b/power/power-8996.c
new file mode 100644
index 0000000..85cc388
--- /dev/null
+++ b/power/power-8996.c
@@ -0,0 +1,334 @@
+/*
+ * 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_NDEBUG 1
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
+#define LOG_TAG "QCOM PowerHAL"
+#include
+#include
+#include
+#include
+
+#include "utils.h"
+#include "metadata-defs.h"
+#include "hint-data.h"
+#include "performance.h"
+#include "power-common.h"
+
+static int display_hint_sent;
+int launch_handle = -1;
+int launch_mode;
+
+#ifdef EXTRA_POWERHAL_HINTS
+static int process_cam_preview_hint(void *metadata)
+{
+ char governor[80];
+ struct cam_preview_metadata_t cam_preview_metadata;
+
+ if (get_scaling_governor(governor, sizeof(governor)) == -1) {
+ ALOGE("Can't obtain scaling governor.");
+
+ return HINT_NONE;
+ }
+
+ /* Initialize encode metadata struct fields */
+ memset(&cam_preview_metadata, 0, sizeof(struct cam_preview_metadata_t));
+ cam_preview_metadata.state = -1;
+ cam_preview_metadata.hint_id = CAM_PREVIEW_HINT_ID;
+
+ if (metadata) {
+ if (parse_cam_preview_metadata((char *)metadata, &cam_preview_metadata) ==
+ -1) {
+ ALOGE("Error occurred while parsing metadata.");
+ return HINT_NONE;
+ }
+ } else {
+ return HINT_NONE;
+ }
+
+ if (cam_preview_metadata.state == 1) {
+ if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
+ (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
+ /* sched and cpufreq params
+ * above_hispeed_delay for LVT - 40ms
+ * go hispeed load for LVT - 95
+ * hispeed freq for LVT - 556 MHz
+ * target load for LVT - 90
+ * above hispeed delay for sLVT - 40ms
+ * go hispeed load for sLVT - 95
+ * hispeed freq for sLVT - 556 MHz
+ * target load for sLVT - 90
+ * bus DCVS set to V2 config:
+ * low power ceil mpbs - 2500
+ * low power io percent - 50
+ */
+ int resource_values[] = {0x41400000, 0x4, 0x41410000, 0x5F, 0x41414000, 0x22C,
+ 0x41420000, 0x5A, 0x41400100, 0x4, 0x41410100, 0x5F, 0x41414100, 0x22C,
+ 0x41420100, 0x5A, 0x41810000, 0x9C4, 0x41814000, 0x32};
+
+ perform_hint_action(cam_preview_metadata.hint_id,
+ resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
+ ALOGI("Cam Preview hint start");
+ return HINT_HANDLED;
+ } else if ((strncmp(governor, SCHED_GOVERNOR, strlen(SCHED_GOVERNOR)) == 0) &&
+ (strlen(governor) == strlen(SCHED_GOVERNOR))) {
+ /*
+ * lower bus BW to save power
+ * 0x41810000: low power ceil mpbs = 2500
+ * 0x41814000: low power io percent = 50
+ */
+ int resource_values[] = {0x41810000, 0x9C4, 0x41814000, 0x32};
+
+ perform_hint_action(
+ cam_preview_metadata.hint_id, resource_values,
+ sizeof(resource_values) / sizeof(resource_values[0]));
+ ALOGI("Cam Preview hint start");
+ return HINT_HANDLED;
+ }
+ } else if (cam_preview_metadata.state == 0) {
+ if (((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
+ (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) ||
+ ((strncmp(governor, SCHED_GOVERNOR, strlen(SCHED_GOVERNOR)) == 0) &&
+ (strlen(governor) == strlen(SCHED_GOVERNOR)))) {
+ undo_hint_action(cam_preview_metadata.hint_id);
+ ALOGI("Cam Preview hint stop");
+ return HINT_HANDLED;
+ }
+ }
+ return HINT_NONE;
+}
+#endif
+
+static int process_boost(int boost_handle, int duration)
+{
+ char governor[80];
+ int eas_launch_resources[] = {0x40804000, 0xFFF, 0x40804100, 0xFFF,
+ 0x40800000, 0xFFF, 0x40800100, 0xFFF,
+ 0x41800000, 140, 0x40400000, 0x1};
+ int hmp_launch_resources[] = {0x40C00000, 0x1, 0x40804000, 0xFFF,
+ 0x40804100, 0xFFF, 0x40800000, 0xFFF,
+ 0x40800100, 0xFFF, 0x41800000, 140,
+ 0x40400000, 0x1};
+ int* launch_resources;
+ size_t launch_resources_size;
+
+ if (get_scaling_governor(governor, sizeof(governor)) == -1) {
+ ALOGE("Can't obtain scaling governor.");
+ return -1;
+ }
+ if (strncmp(governor, SCHED_GOVERNOR, strlen(SCHED_GOVERNOR)) == 0) {
+ launch_resources = eas_launch_resources;
+ launch_resources_size = sizeof(eas_launch_resources) / sizeof(eas_launch_resources[0]);
+ } else if (strncmp(governor, INTERACTIVE_GOVERNOR,
+ strlen(INTERACTIVE_GOVERNOR)) == 0) { /*HMP boost*/
+ launch_resources = hmp_launch_resources;
+ launch_resources_size = sizeof(hmp_launch_resources) / sizeof(hmp_launch_resources[0]);
+ } else {
+ ALOGE("Unsupported governor.");
+ return -1;
+ }
+ boost_handle = interaction_with_handle(
+ boost_handle, duration, launch_resources_size, launch_resources);
+ return boost_handle;
+}
+
+static int process_video_encode_hint(void *metadata)
+{
+ char governor[80];
+ static int boost_handle = -1;
+
+ if (get_scaling_governor(governor, sizeof(governor)) == -1) {
+ ALOGE("Can't obtain scaling governor.");
+
+ return HINT_NONE;
+ }
+
+ if (metadata) {
+ int duration = 2000; // boosts 2s for starting encoding
+ boost_handle = process_boost(boost_handle, duration);
+ ALOGD("LAUNCH ENCODER-ON: %d MS", duration);
+ if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
+ (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
+ /* 1. cpufreq params
+ * -above_hispeed_delay for LVT - 40ms
+ * -go hispeed load for LVT - 95
+ * -hispeed freq for LVT - 556 MHz
+ * -target load for LVT - 90
+ * -above hispeed delay for sLVT - 40ms
+ * -go hispeed load for sLVT - 95
+ * -hispeed freq for sLVT - 806 MHz
+ * -target load for sLVT - 90
+ * 2. bus DCVS set to V2 config:
+ * -low power ceil mpbs - 2500
+ * -low power io percent - 50
+ * 3. hysteresis optimization
+ * -bus dcvs hysteresis tuning
+ * -sample_ms of 10 ms
+ * -disable ignore_hispeed_notif
+ * -sLVT hispeed freq to 806MHz
+ */
+ int resource_values[] = {
+ 0x41810000, 0x9C4, 0x41814000, 0x32, 0x4180C000, 0x0, 0x41820000, 0xA,
+ 0x41438100, 0x1, 0x41438000, 0x1 };
+
+ perform_hint_action(DEFAULT_VIDEO_ENCODE_HINT_ID,
+ resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
+ ALOGD("Video Encode hint start");
+ return HINT_HANDLED;
+ } else if ((strncmp(governor, SCHED_GOVERNOR, strlen(SCHED_GOVERNOR)) == 0) &&
+ (strlen(governor) == strlen(SCHED_GOVERNOR))) {
+
+ /* 1. bus DCVS set to V2 config:
+ * 0x41810000: low power ceil mpbs - 2500
+ * 0x41814000: low power io percent - 50
+ * 2. hysteresis optimization
+ * 0x4180C000: bus dcvs hysteresis tuning
+ * 0x41820000: sample_ms of 10 ms
+ */
+ int resource_values[] = {0x41810000, 0x9C4, 0x41814000, 0x32,
+ 0x4180C000, 0x0, 0x41820000, 0xA};
+
+ perform_hint_action(DEFAULT_VIDEO_ENCODE_HINT_ID,
+ resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
+ ALOGD("Video Encode hint start");
+ return HINT_HANDLED;
+ }
+ } else {
+ // boost handle is intentionally not released, release_request(boost_handle);
+ if (((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
+ (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) ||
+ ((strncmp(governor, SCHED_GOVERNOR, strlen(SCHED_GOVERNOR)) == 0) &&
+ (strlen(governor) == strlen(SCHED_GOVERNOR)))) {
+ undo_hint_action(DEFAULT_VIDEO_ENCODE_HINT_ID);
+ ALOGD("Video Encode hint stop");
+ return HINT_HANDLED;
+ }
+ }
+ return HINT_NONE;
+}
+
+static int process_activity_launch_hint(void *data)
+{
+ // boost will timeout in 5s
+ int duration = 5000;
+ ATRACE_BEGIN("launch");
+ if (sustained_performance_mode || vr_mode) {
+ ATRACE_END();
+ return HINT_HANDLED;
+ }
+
+ ALOGD("LAUNCH HINT: %s", data ? "ON" : "OFF");
+ if (data && launch_mode == 0) {
+ launch_handle = process_boost(launch_handle, duration);
+ if (launch_handle > 0) {
+ launch_mode = 1;
+ ALOGD("Activity launch hint handled");
+ ATRACE_INT("launch_lock", 1);
+ ATRACE_END();
+ return HINT_HANDLED;
+ } else {
+ ATRACE_END();
+ return HINT_NONE;
+ }
+ } else if (data == NULL && launch_mode == 1) {
+ release_request(launch_handle);
+ ATRACE_INT("launch_lock", 0);
+ launch_mode = 0;
+ ATRACE_END();
+ return HINT_HANDLED;
+ }
+ ATRACE_END();
+ return HINT_NONE;
+}
+
+int power_hint_override(power_hint_t hint, void *data)
+{
+ int ret_val = HINT_NONE;
+ switch(hint) {
+#ifdef EXTRA_POWERHAL_HINTS
+ case POWER_HINT_CAM_PREVIEW:
+ ret_val = process_cam_preview_hint(data);
+ break;
+#endif
+ case POWER_HINT_VIDEO_ENCODE:
+ ret_val = process_video_encode_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)
+{
+ return HINT_HANDLED; /* Don't excecute this code path, not in use */
+ char governor[80];
+
+ if (get_scaling_governor(governor, sizeof(governor)) == -1) {
+ ALOGE("Can't obtain scaling governor.");
+
+ return HINT_NONE;
+ }
+
+ if (!on) {
+ /* Display off */
+ if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
+ (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
+ int resource_values[] = {}; /* dummy node */
+ if (!display_hint_sent) {
+ perform_hint_action(DISPLAY_STATE_HINT_ID,
+ resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
+ display_hint_sent = 1;
+ ALOGV("Display Off hint start");
+ return HINT_HANDLED;
+ }
+ }
+ } else {
+ /* Display on */
+ if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
+ (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
+ undo_hint_action(DISPLAY_STATE_HINT_ID);
+ display_hint_sent = 0;
+ ALOGV("Display Off hint stop");
+ return HINT_HANDLED;
+ }
+ }
+ return HINT_NONE;
+}
diff --git a/power/power-common.h b/power/power-common.h
new file mode 100644
index 0000000..0b2680c
--- /dev/null
+++ b/power/power-common.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013, 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 NODE_MAX (64)
+
+#define SCALING_GOVERNOR_PATH "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
+#define DCVS_CPU0_SLACK_MAX_NODE "/sys/module/msm_dcvs/cores/cpu0/slack_time_max_us"
+#define DCVS_CPU0_SLACK_MIN_NODE "/sys/module/msm_dcvs/cores/cpu0/slack_time_min_us"
+#define MPDECISION_SLACK_MAX_NODE "/sys/module/msm_mpdecision/slack_time_max_us"
+#define MPDECISION_SLACK_MIN_NODE "/sys/module/msm_mpdecision/slack_time_min_us"
+#define SCALING_MIN_FREQ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq"
+#define ONDEMAND_GOVERNOR "ondemand"
+#define INTERACTIVE_GOVERNOR "interactive"
+#define MSMDCVS_GOVERNOR "msm-dcvs"
+#define SCHED_GOVERNOR "sched"
+
+#define HINT_HANDLED (0)
+#define HINT_NONE (-1)
+
+enum CPU_GOV_CHECK {
+ CPU0 = 0,
+ CPU1 = 1,
+ CPU2 = 2,
+ CPU3 = 3
+};
+
+#define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
+
diff --git a/power/power-helper.c b/power/power-helper.c
new file mode 100644
index 0000000..7b625b6
--- /dev/null
+++ b/power/power-helper.c
@@ -0,0 +1,620 @@
+/*
+ * Copyright (c) 2012-2013, 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_NDEBUG 1
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define LOG_TAG "QCOM PowerHAL"
+#include
+#include
+#include
+
+#include "utils.h"
+#include "metadata-defs.h"
+#include "hint-data.h"
+#include "performance.h"
+#include "power-common.h"
+#include "power-helper.h"
+
+#define USINSEC 1000000L
+#define NSINUS 1000L
+
+#ifndef RPM_STAT
+#define RPM_STAT "/d/rpm_stats"
+#endif
+
+#ifndef RPM_MASTER_STAT
+#define RPM_MASTER_STAT "/d/rpm_master_stats"
+#endif
+
+static const char *rpm_param_names[] = {
+ "vlow_count",
+ "accumulated_vlow_time",
+ "vmin_count",
+ "accumulated_vmin_time"
+};
+
+static const char *rpm_master_param_names[] = {
+ "xo_accumulated_duration",
+ "xo_count",
+ "xo_accumulated_duration",
+ "xo_count",
+ "xo_accumulated_duration",
+ "xo_count",
+ "xo_accumulated_duration",
+ "xo_count"
+};
+
+
+static int saved_dcvs_cpu0_slack_max = -1;
+static int saved_dcvs_cpu0_slack_min = -1;
+static int saved_mpdecision_slack_max = -1;
+static int saved_mpdecision_slack_min = -1;
+static int saved_interactive_mode = -1;
+static int slack_node_rw_failed = 0;
+static int display_hint_sent;
+int display_boost;
+static int sustained_mode_handle = 0;
+static int vr_mode_handle = 0;
+int sustained_performance_mode = 0;
+int vr_mode = 0;
+
+//interaction boost global variables
+static struct timespec s_previous_boost_timespec;
+static int s_previous_duration;
+
+void power_init(void)
+{
+ ALOGV("QCOM power HAL initing.");
+
+ int fd;
+ char buf[10] = {0};
+
+ fd = open("/sys/devices/soc0/soc_id", O_RDONLY);
+ if (fd >= 0) {
+ if (read(fd, buf, sizeof(buf) - 1) == -1) {
+ ALOGW("Unable to read soc_id");
+ } else {
+ int soc_id = atoi(buf);
+ if (soc_id == 194 || (soc_id >= 208 && soc_id <= 218) || soc_id == 178) {
+ display_boost = 1;
+ }
+ }
+ close(fd);
+ }
+}
+
+int __attribute__ ((weak)) power_hint_override(power_hint_t UNUSED(hint),
+ void * UNUSED(data))
+{
+ return HINT_NONE;
+}
+
+/* Declare function before use */
+void interaction(int duration, int num_args, int opt_list[]);
+void release_request(int lock_handle);
+
+static long long calc_timespan_us(struct timespec start, struct timespec end) {
+ long long diff_in_us = 0;
+ diff_in_us += (end.tv_sec - start.tv_sec) * USINSEC;
+ diff_in_us += (end.tv_nsec - start.tv_nsec) / NSINUS;
+ return diff_in_us;
+}
+
+void power_hint(power_hint_t hint, void *data)
+{
+ /* Check if this hint has been overridden. */
+ if (power_hint_override(hint, data) == HINT_HANDLED) {
+ /* The power_hint has been handled. We can skip the rest. */
+ return;
+ }
+
+ switch(hint) {
+ case POWER_HINT_VSYNC:
+ break;
+ /* Sustained performance mode:
+ * All CPUs are capped to ~1.2GHz
+ * GPU frequency is capped to 315MHz
+ */
+ /* VR+Sustained performance mode:
+ * All CPUs are locked to ~1.2GHz
+ * GPU frequency is locked to 315MHz
+ * GPU BW min_freq is raised to 775MHz
+ */
+ case POWER_HINT_SUSTAINED_PERFORMANCE:
+ {
+ int duration = 0;
+ if (data && sustained_performance_mode == 0) {
+ int* resources;
+ if (vr_mode == 0) { // Sustained mode only.
+ // Ensure that POWER_HINT_LAUNCH is not in progress.
+ if (launch_mode == 1) {
+ release_request(launch_handle);
+ launch_mode = 0;
+ }
+ // 0x40804000: cpu0 max freq
+ // 0x40804100: cpu2 max freq
+ // 0x42C20000: gpu max freq
+ // 0x42C24000: gpu min freq
+ // 0x42C28000: gpu bus min freq
+ int resources[] = {0x40804000, 1209, 0x40804100, 1209,
+ 0x42C24000, 133, 0x42C20000, 315,
+ 0x42C28000, 7759};
+ sustained_mode_handle = interaction_with_handle(
+ sustained_mode_handle, duration,
+ sizeof(resources) / sizeof(resources[0]), resources);
+ } else if (vr_mode == 1) { // Sustained + VR mode.
+ release_request(vr_mode_handle);
+ // 0x40804000: cpu0 max freq
+ // 0x40804100: cpu2 max freq
+ // 0x40800000: cpu0 min freq
+ // 0x40800100: cpu2 min freq
+ // 0x42C20000: gpu max freq
+ // 0x42C24000: gpu min freq
+ // 0x42C28000: gpu bus min freq
+ int resources[] = {0x40800000, 1209, 0x40800100, 1209,
+ 0x40804000, 1209, 0x40804100, 1209,
+ 0x42C24000, 315, 0x42C20000, 315,
+ 0x42C28000, 7759};
+ sustained_mode_handle = interaction_with_handle(
+ sustained_mode_handle, duration,
+ sizeof(resources) / sizeof(resources[0]), resources);
+ }
+ sustained_performance_mode = 1;
+ } else if (sustained_performance_mode == 1) {
+ release_request(sustained_mode_handle);
+ if (vr_mode == 1) { // Switch back to VR Mode.
+ // 0x40804000: cpu0 max freq
+ // 0x40804100: cpu2 max freq
+ // 0x40800000: cpu0 min freq
+ // 0x40800100: cpu2 min freq
+ // 0x42C20000: gpu max freq
+ // 0x42C24000: gpu min freq
+ // 0x42C28000: gpu bus min freq
+ int resources[] = {0x40804000, 1440, 0x40804100, 1440,
+ 0x40800000, 1440, 0x40800100, 1440,
+ 0x42C20000, 510, 0x42C24000, 510,
+ 0x42C28000, 7759};
+ vr_mode_handle = interaction_with_handle(
+ vr_mode_handle, duration,
+ sizeof(resources) / sizeof(resources[0]), resources);
+ }
+ sustained_performance_mode = 0;
+ }
+ }
+ break;
+ /* VR mode:
+ * All CPUs are locked at ~1.4GHz
+ * GPU frequency is locked to 510MHz
+ * GPU BW min_freq is raised to 775MHz
+ */
+ case POWER_HINT_VR_MODE:
+ {
+ int duration = 0;
+ if (data && vr_mode == 0) {
+ if (sustained_performance_mode == 0) { // VR mode only.
+ // Ensure that POWER_HINT_LAUNCH is not in progress.
+ if (launch_mode == 1) {
+ release_request(launch_handle);
+ launch_mode = 0;
+ }
+ // 0x40804000: cpu0 max freq
+ // 0x40804100: cpu2 max freq
+ // 0x40800000: cpu0 min freq
+ // 0x40800100: cpu2 min freq
+ // 0x42C20000: gpu max freq
+ // 0x42C24000: gpu min freq
+ // 0x42C28000: gpu bus min freq
+ int resources[] = {0x40800000, 1440, 0x40800100, 1440,
+ 0x40804000, 1440, 0x40804100, 1440,
+ 0x42C20000, 510, 0x42C24000, 510,
+ 0x42C28000, 7759};
+ vr_mode_handle = interaction_with_handle(
+ vr_mode_handle, duration,
+ sizeof(resources) / sizeof(resources[0]), resources);
+ } else if (sustained_performance_mode == 1) { // Sustained + VR mode.
+ release_request(sustained_mode_handle);
+ // 0x40804000: cpu0 max freq
+ // 0x40804100: cpu2 max freq
+ // 0x40800000: cpu0 min freq
+ // 0x40800100: cpu2 min freq
+ // 0x42C20000: gpu max freq
+ // 0x42C24000: gpu min freq
+ // 0x42C28000: gpu bus min freq
+ int resources[] = {0x40800000, 1209, 0x40800100, 1209,
+ 0x40804000, 1209, 0x40804100, 1209,
+ 0x42C24000, 315, 0x42C20000, 315,
+ 0x42C28000, 7759};
+
+ vr_mode_handle = interaction_with_handle(
+ vr_mode_handle, duration,
+ sizeof(resources) / sizeof(resources[0]), resources);
+ }
+ vr_mode = 1;
+ } else if (vr_mode == 1) {
+ release_request(vr_mode_handle);
+ if (sustained_performance_mode == 1) { // Switch back to sustained Mode.
+ // 0x40804000: cpu0 max freq
+ // 0x40804100: cpu2 max freq
+ // 0x40800000: cpu0 min freq
+ // 0x40800100: cpu2 min freq
+ // 0x42C20000: gpu max freq
+ // 0x42C24000: gpu min freq
+ // 0x42C28000: gpu bus min freq
+ int resources[] = {0x40800000, 0, 0x40800100, 0,
+ 0x40804000, 1209, 0x40804100, 1209,
+ 0x42C24000, 133, 0x42C20000, 315,
+ 0x42C28000, 0};
+ sustained_mode_handle = interaction_with_handle(
+ sustained_mode_handle, duration,
+ sizeof(resources) / sizeof(resources[0]), resources);
+ }
+ vr_mode = 0;
+ }
+ }
+ break;
+ case POWER_HINT_INTERACTION:
+ {
+ char governor[80];
+
+ if (get_scaling_governor(governor, sizeof(governor)) == -1) {
+ ALOGE("Can't obtain scaling governor.");
+ return;
+ }
+
+ if (sustained_performance_mode || vr_mode) {
+ return;
+ }
+
+ int duration = 1500; // 1.5s by default
+ if (data) {
+ int input_duration = *((int*)data) + 750;
+ if (input_duration > duration) {
+ duration = (input_duration > 5750) ? 5750 : input_duration;
+ }
+ }
+
+ struct timespec cur_boost_timespec;
+ clock_gettime(CLOCK_MONOTONIC, &cur_boost_timespec);
+
+ long long 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;
+ }
+ s_previous_boost_timespec = cur_boost_timespec;
+ s_previous_duration = duration;
+
+ // Scheduler is EAS.
+ if (true || strncmp(governor, SCHED_GOVERNOR, strlen(SCHED_GOVERNOR)) == 0) {
+ // Setting the value of foreground schedtune boost to 50 and
+ // scaling_min_freq to 1100MHz.
+ int resources[] = {0x40800000, 1100, 0x40800100, 1100, 0x42C0C000, 0x32, 0x41800000, 0x33};
+ interaction(duration, sizeof(resources)/sizeof(resources[0]), resources);
+ } else { // Scheduler is HMP.
+ int resources[] = {0x41800000, 0x33, 0x40800000, 1000, 0x40800100, 1000, 0x40C00000, 0x1};
+ interaction(duration, sizeof(resources)/sizeof(resources[0]), resources);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+int __attribute__ ((weak)) set_interactive_override(int UNUSED(on))
+{
+ return HINT_NONE;
+}
+
+void power_set_interactive(int on)
+{
+ char governor[80];
+ char tmp_str[NODE_MAX];
+ struct video_encode_metadata_t video_encode_metadata;
+ int rc = 0;
+
+ if (set_interactive_override(on) == HINT_HANDLED) {
+ return;
+ }
+
+ ALOGV("Got set_interactive hint");
+
+ if (get_scaling_governor(governor, sizeof(governor)) == -1) {
+ ALOGE("Can't obtain scaling governor.");
+
+ return;
+ }
+
+ if (!on) {
+ /* Display off. */
+ if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
+ (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
+ int resource_values[] = {DISPLAY_OFF, MS_500, THREAD_MIGRATION_SYNC_OFF};
+
+ if (!display_hint_sent) {
+ perform_hint_action(DISPLAY_STATE_HINT_ID,
+ resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
+ display_hint_sent = 1;
+ }
+ } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
+ (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
+ int resource_values[] = {TR_MS_50, THREAD_MIGRATION_SYNC_OFF};
+
+ if (!display_hint_sent) {
+ perform_hint_action(DISPLAY_STATE_HINT_ID,
+ resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
+ display_hint_sent = 1;
+ }
+ } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) &&
+ (strlen(governor) == strlen(MSMDCVS_GOVERNOR))) {
+ if (saved_interactive_mode == 1){
+ /* Display turned off. */
+ if (sysfs_read(DCVS_CPU0_SLACK_MAX_NODE, tmp_str, NODE_MAX - 1)) {
+ if (!slack_node_rw_failed) {
+ ALOGE("Failed to read from %s", DCVS_CPU0_SLACK_MAX_NODE);
+ }
+
+ rc = 1;
+ } else {
+ saved_dcvs_cpu0_slack_max = atoi(tmp_str);
+ }
+
+ if (sysfs_read(DCVS_CPU0_SLACK_MIN_NODE, tmp_str, NODE_MAX - 1)) {
+ if (!slack_node_rw_failed) {
+ ALOGE("Failed to read from %s", DCVS_CPU0_SLACK_MIN_NODE);
+ }
+
+ rc = 1;
+ } else {
+ saved_dcvs_cpu0_slack_min = atoi(tmp_str);
+ }
+
+ if (sysfs_read(MPDECISION_SLACK_MAX_NODE, tmp_str, NODE_MAX - 1)) {
+ if (!slack_node_rw_failed) {
+ ALOGE("Failed to read from %s", MPDECISION_SLACK_MAX_NODE);
+ }
+
+ rc = 1;
+ } else {
+ saved_mpdecision_slack_max = atoi(tmp_str);
+ }
+
+ if (sysfs_read(MPDECISION_SLACK_MIN_NODE, tmp_str, NODE_MAX - 1)) {
+ if(!slack_node_rw_failed) {
+ ALOGE("Failed to read from %s", MPDECISION_SLACK_MIN_NODE);
+ }
+
+ rc = 1;
+ } else {
+ saved_mpdecision_slack_min = atoi(tmp_str);
+ }
+
+ /* Write new values. */
+ if (saved_dcvs_cpu0_slack_max != -1) {
+ snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_dcvs_cpu0_slack_max);
+
+ if (sysfs_write(DCVS_CPU0_SLACK_MAX_NODE, tmp_str) != 0) {
+ if (!slack_node_rw_failed) {
+ ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MAX_NODE);
+ }
+
+ rc = 1;
+ }
+ }
+
+ if (saved_dcvs_cpu0_slack_min != -1) {
+ snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_dcvs_cpu0_slack_min);
+
+ if (sysfs_write(DCVS_CPU0_SLACK_MIN_NODE, tmp_str) != 0) {
+ if(!slack_node_rw_failed) {
+ ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MIN_NODE);
+ }
+
+ rc = 1;
+ }
+ }
+
+ if (saved_mpdecision_slack_max != -1) {
+ snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_mpdecision_slack_max);
+
+ if (sysfs_write(MPDECISION_SLACK_MAX_NODE, tmp_str) != 0) {
+ if(!slack_node_rw_failed) {
+ ALOGE("Failed to write to %s", MPDECISION_SLACK_MAX_NODE);
+ }
+
+ rc = 1;
+ }
+ }
+
+ if (saved_mpdecision_slack_min != -1) {
+ snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_mpdecision_slack_min);
+
+ if (sysfs_write(MPDECISION_SLACK_MIN_NODE, tmp_str) != 0) {
+ if(!slack_node_rw_failed) {
+ ALOGE("Failed to write to %s", MPDECISION_SLACK_MIN_NODE);
+ }
+
+ rc = 1;
+ }
+ }
+ }
+
+ slack_node_rw_failed = rc;
+ }
+ } else {
+ /* Display on. */
+ if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
+ (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
+ undo_hint_action(DISPLAY_STATE_HINT_ID);
+ display_hint_sent = 0;
+ } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
+ (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
+ undo_hint_action(DISPLAY_STATE_HINT_ID);
+ display_hint_sent = 0;
+ } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) &&
+ (strlen(governor) == strlen(MSMDCVS_GOVERNOR))) {
+ if (saved_interactive_mode == -1 || saved_interactive_mode == 0) {
+ /* Display turned on. Restore if possible. */
+ if (saved_dcvs_cpu0_slack_max != -1) {
+ snprintf(tmp_str, NODE_MAX, "%d", saved_dcvs_cpu0_slack_max);
+
+ if (sysfs_write(DCVS_CPU0_SLACK_MAX_NODE, tmp_str) != 0) {
+ if (!slack_node_rw_failed) {
+ ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MAX_NODE);
+ }
+
+ rc = 1;
+ }
+ }
+
+ if (saved_dcvs_cpu0_slack_min != -1) {
+ snprintf(tmp_str, NODE_MAX, "%d", saved_dcvs_cpu0_slack_min);
+
+ if (sysfs_write(DCVS_CPU0_SLACK_MIN_NODE, tmp_str) != 0) {
+ if (!slack_node_rw_failed) {
+ ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MIN_NODE);
+ }
+
+ rc = 1;
+ }
+ }
+
+ if (saved_mpdecision_slack_max != -1) {
+ snprintf(tmp_str, NODE_MAX, "%d", saved_mpdecision_slack_max);
+
+ if (sysfs_write(MPDECISION_SLACK_MAX_NODE, tmp_str) != 0) {
+ if (!slack_node_rw_failed) {
+ ALOGE("Failed to write to %s", MPDECISION_SLACK_MAX_NODE);
+ }
+
+ rc = 1;
+ }
+ }
+
+ if (saved_mpdecision_slack_min != -1) {
+ snprintf(tmp_str, NODE_MAX, "%d", saved_mpdecision_slack_min);
+
+ if (sysfs_write(MPDECISION_SLACK_MIN_NODE, tmp_str) != 0) {
+ if (!slack_node_rw_failed) {
+ ALOGE("Failed to write to %s", MPDECISION_SLACK_MIN_NODE);
+ }
+
+ rc = 1;
+ }
+ }
+ }
+
+ slack_node_rw_failed = rc;
+ }
+ }
+
+ saved_interactive_mode = !!on;
+}
+
+
+static int extract_stats(uint64_t *list, char *file, const char**param_names,
+ unsigned int num_parameters, int isHex) {
+ FILE *fp;
+ ssize_t read;
+ size_t len;
+ size_t index = 0;
+ char *line;
+ int ret;
+
+ fp = fopen(file, "r");
+ if (fp == NULL) {
+ ret = -errno;
+ ALOGE("%s: failed to open: %s Error = %s", __func__, file, strerror(errno));
+ return ret;
+ }
+
+ for (line = NULL, len = 0;
+ ((read = getline(&line, &len, fp) != -1) && (index < num_parameters));
+ free(line), line = NULL, len = 0) {
+ uint64_t value;
+ char* offset;
+
+ size_t begin = strspn(line, " \t");
+ if (strncmp(line + begin, param_names[index], strlen(param_names[index]))) {
+ continue;
+ }
+
+ offset = memchr(line, ':', len);
+ if (!offset) {
+ continue;
+ }
+
+ if (isHex) {
+ sscanf(offset, ":%" SCNx64, &value);
+ } else {
+ sscanf(offset, ":%" SCNu64, &value);
+ }
+ list[index] = value;
+ index++;
+ }
+
+ free(line);
+ fclose(fp);
+
+ return 0;
+}
+
+
+int extract_platform_stats(uint64_t *list) {
+
+ int ret;
+
+ //Data is located in two files
+
+ ret = extract_stats(list, RPM_STAT, rpm_param_names, RPM_PARAM_COUNT, false);
+ if (ret) {
+ for (size_t i=0; i < RPM_PARAM_COUNT; i++)
+ list[i] = 0;
+ }
+
+ ret = extract_stats(list + RPM_PARAM_COUNT, RPM_MASTER_STAT,
+ rpm_master_param_names, PLATFORM_PARAM_COUNT - RPM_PARAM_COUNT, true);
+ if (ret) {
+ for (size_t i=RPM_PARAM_COUNT; i < PLATFORM_PARAM_COUNT; i++)
+ list[i] = 0;
+ }
+
+ return 0;
+}
diff --git a/power/power-helper.h b/power/power-helper.h
new file mode 100644
index 0000000..77947d4
--- /dev/null
+++ b/power/power-helper.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+#ifndef __POWER_HELPER_H__
+#define __POWER_HELPER_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+
+enum platform_param_id {
+ VLOW_COUNT = 0,
+ ACCUMULATED_VLOW_TIME,
+ VMIN_COUNT,
+ ACCUMULATED_VMIN_TIME,
+ RPM_PARAM_COUNT,
+
+ XO_ACCUMULATED_DURATION_APSS = RPM_PARAM_COUNT,
+ XO_COUNT_APSS,
+ XO_ACCUMULATED_DURATION_MPSS,
+ XO_COUNT_MPSS,
+ XO_ACCUMULATED_DURATION_ADSP,
+ XO_COUNT_ADSP,
+ XO_ACCUMULATED_DURATION_SLPI,
+ XO_COUNT_SLPI,
+
+ //Don't add any lines after that line
+ PLATFORM_PARAM_COUNT
+};
+
+enum platform_mode_id {
+ RPM_MODE_XO = 0,
+ RPM_MODE_VMIN,
+
+ //Don't add any lines after that line
+ RPM_MODE_COUNT
+};
+
+#define XO_VOTERS 4
+#define VMIN_VOTERS 0
+
+enum voter_id {
+ APSS,
+ MPSS,
+ ADSP,
+ SLPI,
+
+ //Don't add any lines after that line
+ VOTER_COUNT
+};
+
+void power_init(void);
+void power_hint(power_hint_t hint, void *data);
+void power_set_interactive(int on);
+int extract_platform_stats(uint64_t *list);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__POWER_HELPER_H__
diff --git a/power/service.cpp b/power/service.cpp
new file mode 100644
index 0000000..655d222
--- /dev/null
+++ b/power/service.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.power@1.1-service.gts3l"
+
+#include
+#include
+#include
+#include "Power.h"
+
+using android::sp;
+using android::status_t;
+using android::OK;
+
+// libhwbinder:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::power::V1_1::IPower;
+using android::hardware::power::V1_1::implementation::Power;
+
+int main() {
+
+ status_t status;
+ android::sp service = nullptr;
+
+ ALOGI("Power HAL Service 1.1 for Samsung Galaxy Tab S3 is starting.");
+
+ service = new Power();
+ if (service == nullptr) {
+ ALOGE("Can not create an instance of Power HAL Iface, exiting.");
+
+ goto shutdown;
+ }
+
+ configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+ status = service->registerAsService();
+ if (status != OK) {
+ ALOGE("Could not register service for Power HAL Iface (%d).", status);
+ goto shutdown;
+ }
+
+ ALOGI("Power Service is ready");
+ joinRpcThreadpool();
+ //Should not pass this line
+
+shutdown:
+ // In normal operation, we don't expect the thread pool to exit
+
+ ALOGE("Power Service is shutting down");
+ return 1;
+}
diff --git a/power/utils.c b/power/utils.c
new file mode 100644
index 0000000..bd3f354
--- /dev/null
+++ b/power/utils.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2012-2013, 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_NDEBUG 1
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "utils.h"
+#include "list.h"
+#include "hint-data.h"
+#include "power-common.h"
+
+#define LOG_TAG "QCOM PowerHAL"
+#include
+
+#ifndef INTERACTION_BOOST
+#define INTERACTION_BOOST
+#endif
+
+char scaling_gov_path[4][80] ={
+ "sys/devices/system/cpu/cpu0/cpufreq/scaling_governor",
+ "sys/devices/system/cpu/cpu1/cpufreq/scaling_governor",
+ "sys/devices/system/cpu/cpu2/cpufreq/scaling_governor",
+ "sys/devices/system/cpu/cpu3/cpufreq/scaling_governor"
+};
+
+static void *qcopt_handle;
+static int (*perf_lock_acq)(unsigned long handle, int duration,
+ int list[], int numArgs);
+static int (*perf_lock_rel)(unsigned long handle);
+static struct list_node active_hint_list_head;
+
+static void *get_qcopt_handle()
+{
+ char qcopt_lib_path[PATH_MAX] = {0};
+ void *handle = NULL;
+
+ dlerror();
+
+ if (property_get("ro.vendor.extension_library", qcopt_lib_path,
+ NULL)) {
+ handle = dlopen(qcopt_lib_path, RTLD_NOW);
+ if (!handle) {
+ ALOGE("Unable to open %s: %s\n", qcopt_lib_path,
+ dlerror());
+ }
+ }
+
+ return handle;
+}
+
+static void __attribute__ ((constructor)) initialize(void)
+{
+ qcopt_handle = get_qcopt_handle();
+
+ if (!qcopt_handle) {
+ ALOGE("Failed to get qcopt handle.\n");
+ } else {
+ /*
+ * qc-opt handle obtained. Get the perflock acquire/release
+ * function pointers.
+ */
+ perf_lock_acq = dlsym(qcopt_handle, "perf_lock_acq");
+
+ if (!perf_lock_acq) {
+ ALOGE("Unable to get perf_lock_acq function handle.\n");
+ }
+
+ perf_lock_rel = dlsym(qcopt_handle, "perf_lock_rel");
+
+ if (!perf_lock_rel) {
+ ALOGE("Unable to get perf_lock_rel function handle.\n");
+ }
+ }
+}
+
+static void __attribute__ ((destructor)) cleanup(void)
+{
+ if (qcopt_handle) {
+ if (dlclose(qcopt_handle))
+ ALOGE("Error occurred while closing qc-opt library.");
+ }
+}
+
+int sysfs_read(char *path, char *s, int num_bytes)
+{
+ char buf[80];
+ int count;
+ int ret = 0;
+ int fd = open(path, O_RDONLY);
+
+ if (fd < 0) {
+ strerror_r(errno, buf, sizeof(buf));
+ ALOGE("Error opening %s: %s\n", path, buf);
+
+ return -1;
+ }
+
+ if ((count = read(fd, s, num_bytes - 1)) < 0) {
+ strerror_r(errno, buf, sizeof(buf));
+ ALOGE("Error writing to %s: %s\n", path, buf);
+
+ ret = -1;
+ } else {
+ s[count] = '\0';
+ }
+
+ close(fd);
+
+ return ret;
+}
+
+int sysfs_write(char *path, char *s)
+{
+ char buf[80];
+ int len;
+ int ret = 0;
+ int fd = open(path, O_WRONLY);
+
+ if (fd < 0) {
+ strerror_r(errno, buf, sizeof(buf));
+ ALOGE("Error opening %s: %s\n", path, buf);
+ return -1 ;
+ }
+
+ len = write(fd, s, strlen(s));
+ if (len < 0) {
+ strerror_r(errno, buf, sizeof(buf));
+ ALOGE("Error writing to %s: %s\n", path, buf);
+
+ ret = -1;
+ }
+
+ close(fd);
+
+ return ret;
+}
+
+int get_scaling_governor(char governor[], int size)
+{
+ if (sysfs_read(SCALING_GOVERNOR_PATH, governor,
+ size) == -1) {
+ // Can't obtain the scaling governor. Return.
+ return -1;
+ } else {
+ // Strip newline at the end.
+ int len = strlen(governor);
+
+ len--;
+
+ while (len >= 0 && (governor[len] == '\n' || governor[len] == '\r'))
+ governor[len--] = '\0';
+ }
+
+ return 0;
+}
+
+int get_scaling_governor_check_cores(char governor[], int size,int core_num)
+{
+
+ if (sysfs_read(scaling_gov_path[core_num], governor,
+ size) == -1) {
+ // Can't obtain the scaling governor. Return.
+ return -1;
+ }
+
+ // Strip newline at the end.
+ int len = strlen(governor);
+ len--;
+ while (len >= 0 && (governor[len] == '\n' || governor[len] == '\r'))
+ governor[len--] = '\0';
+
+ return 0;
+}
+
+void interaction(int duration, int num_args, int opt_list[])
+{
+#ifdef INTERACTION_BOOST
+ static int lock_handle = 0;
+
+ if (duration < 0 || num_args < 1 || opt_list[0] == 0)
+ return;
+
+ if (qcopt_handle) {
+ if (perf_lock_acq) {
+ lock_handle = perf_lock_acq(lock_handle, duration, opt_list, num_args);
+ if (lock_handle == -1)
+ ALOGE("Failed to acquire lock.");
+ }
+ }
+#endif
+}
+
+int interaction_with_handle(int lock_handle, int duration, int num_args, int opt_list[])
+{
+#ifdef INTERACTION_BOOST
+ if (duration < 0 || num_args < 1 || opt_list[0] == 0)
+ return 0;
+
+ if (qcopt_handle) {
+ if (perf_lock_acq) {
+ lock_handle = perf_lock_acq(lock_handle, duration, opt_list, num_args);
+ if (lock_handle == -1)
+ ALOGE("Failed to acquire lock.");
+ }
+ }
+ return lock_handle;
+#endif
+ return 0;
+}
+
+void release_request(int lock_handle) {
+ if (qcopt_handle && perf_lock_rel)
+ perf_lock_rel(lock_handle);
+}
+
+void perform_hint_action(int hint_id, int resource_values[], int num_resources)
+{
+ if (qcopt_handle) {
+ struct hint_data temp_hint_data = {
+ .hint_id = hint_id
+ };
+ struct list_node *found_node = find_node(&active_hint_list_head,
+ &temp_hint_data);
+ if (found_node) {
+ ALOGE("hint ID %d already active", hint_id);
+ return;
+ }
+ if (perf_lock_acq) {
+ /* Acquire an indefinite lock for the requested resources. */
+ int lock_handle = perf_lock_acq(0, 0, resource_values,
+ num_resources);
+
+ if (lock_handle == -1) {
+ ALOGE("Failed to acquire lock.");
+ } else {
+ /* Add this handle to our internal hint-list. */
+ struct hint_data *new_hint =
+ (struct hint_data *)malloc(sizeof(struct hint_data));
+
+ if (new_hint) {
+ if (!active_hint_list_head.compare) {
+ active_hint_list_head.compare =
+ (int (*)(void *, void *))hint_compare;
+ active_hint_list_head.dump = (void (*)(void *))hint_dump;
+ }
+
+ new_hint->hint_id = hint_id;
+ new_hint->perflock_handle = lock_handle;
+
+ if (add_list_node(&active_hint_list_head, new_hint) == NULL) {
+ free(new_hint);
+ /* Can't keep track of this lock. Release it. */
+ if (perf_lock_rel)
+ perf_lock_rel(lock_handle);
+
+ ALOGE("Failed to process hint.");
+ }
+ } else {
+ /* Can't keep track of this lock. Release it. */
+ if (perf_lock_rel)
+ perf_lock_rel(lock_handle);
+
+ ALOGE("Failed to process hint.");
+ }
+ }
+ }
+ }
+}
+
+void undo_hint_action(int hint_id)
+{
+ if (qcopt_handle) {
+ if (perf_lock_rel) {
+ /* Get hint-data associated with this hint-id */
+ struct list_node *found_node;
+ struct hint_data temp_hint_data = {
+ .hint_id = hint_id
+ };
+
+ found_node = find_node(&active_hint_list_head,
+ &temp_hint_data);
+
+ if (found_node) {
+ /* Release this lock. */
+ struct hint_data *found_hint_data =
+ (struct hint_data *)(found_node->data);
+
+ if (found_hint_data) {
+ if (perf_lock_rel(found_hint_data->perflock_handle) == -1)
+ ALOGE("Perflock release failed: %d", hint_id);
+ }
+
+ if (found_node->data) {
+ /* We can free the hint-data for this node. */
+ free(found_node->data);
+ }
+
+ remove_list_node(&active_hint_list_head, found_node);
+ ALOGV("Undo of hint ID %d succeeded", hint_id);
+ } else {
+ ALOGE("Invalid hint ID: %d", hint_id);
+ }
+ }
+ }
+}
+
+/*
+ * Used to release initial lock holding
+ * two cores online when the display is on
+ */
+void undo_initial_hint_action()
+{
+ if (qcopt_handle) {
+ if (perf_lock_rel) {
+ perf_lock_rel(1);
+ }
+ }
+}
diff --git a/power/utils.h b/power/utils.h
new file mode 100644
index 0000000..8d80971
--- /dev/null
+++ b/power/utils.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+
+#include
+
+extern int launch_handle;
+extern int launch_mode;
+extern int sustained_performance_mode;
+extern int vr_mode;
+
+int sysfs_read(char *path, char *s, int num_bytes);
+int sysfs_write(char *path, char *s);
+int sysfs_get_size_in_bytes(char *path);
+int get_scaling_governor(char governor[], int size);
+int get_scaling_governor_check_cores(char governor[], int size,int core_num);
+
+void vote_ondemand_io_busy_off();
+void unvote_ondemand_io_busy_off();
+void vote_ondemand_sdf_low();
+void unvote_ondemand_sdf_low();
+void perform_hint_action(int hint_id, int resource_values[],
+ int num_resources);
+void undo_hint_action(int hint_id);
+void release_request(int lock_handle);
+int interaction_with_handle(int lock_handle, int duration, int num_args, int opt_list[]);