sdm : Add support for dynamic BW limit management
Read if device need to support dynamic bandwidth limit and
provide framework for applying a new total bandwidth limit and
per pipe bandwidth limit based on application scenario. Also
provide an API to query the status of bandwidth limit transaction.
Change-Id: Iaf9676a45c8c0c0c4af00c81ce4f5d70759c02ba
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index 422ddb2..2d7dddc 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -71,6 +71,7 @@
SET_DISPLAY_MODE = 29, // Set display mode to command or video mode
SET_CAMERA_STATUS = 30, // To notify display when camera is on and off
MIN_HDCP_ENCRYPTION_LEVEL_CHANGED = 31,
+ GET_BW_TRANSACTION_STATUS = 32, //Client can query BW transaction status.
COMMAND_LIST_END = 400,
};
diff --git a/libqservice/QServiceUtils.h b/libqservice/QServiceUtils.h
index 73b2b18..8f25253 100644
--- a/libqservice/QServiceUtils.h
+++ b/libqservice/QServiceUtils.h
@@ -83,4 +83,20 @@
return sendSingleParam(qService::IQService::SET_CAMERA_STATUS, on);
}
+inline bool displayBWTransactionPending() {
+ android::status_t err = (android::status_t) android::FAILED_TRANSACTION;
+ bool ret = false;
+ android::sp<qService::IQService> binder = getBinder();
+ android::Parcel inParcel, outParcel;
+ if(binder != NULL) {
+ err = binder->dispatch(qService::IQService::GET_BW_TRANSACTION_STATUS,
+ &inParcel , &outParcel);
+ if(err != android::NO_ERROR){
+ ALOGE("GET_BW_TRANSACTION_STATUS binder call failed err=%d", err);
+ return ret;
+ }
+ }
+ ret = outParcel.readInt32();
+ return ret;
+}
#endif /* end of include guard: QSERVICEUTILS_H */
diff --git a/sdm/include/core/core_interface.h b/sdm/include/core/core_interface.h
index 26f6e2f..582222f 100644
--- a/sdm/include/core/core_interface.h
+++ b/sdm/include/core/core_interface.h
@@ -76,6 +76,18 @@
*/
class DebugHandler;
+/*! @brief This enum represents max bandwidth limit mode.
+
+ @sa DisplayInterface::SetMaxBandwidthMode
+*/
+enum HWBwModes {
+ kBwDefault, //!< Default state. No change in device bandwidth limit.
+ kBwCamera, //!< Camera is on. Bandwidth limit should be reduced accordingly.
+ kBwVFlip, //!< VFlip is required. Reduce bandwidth limit accordingly.
+ kBwHFlip, //!< HFlip is required. Reduce bandwidth limit accordingly.
+ kBwModeMax, //!< Limiter for maximum available bandwidth modes.
+};
+
/*! @brief Display core interface.
@details This class defines display core interfaces. It contains methods which client shall use
@@ -151,6 +163,16 @@
*/
virtual DisplayError DestroyDisplay(DisplayInterface *interface) = 0;
+ /*! @brief Method to update the bandwidth limit as per given mode.
+
+ @param[in] mode indicate the mode or use case
+
+ @return \link DisplayError \endlink
+
+ */
+ virtual DisplayError SetMaxBandwidthMode(HWBwModes mode) = 0;
+
+
protected:
virtual ~CoreInterface() { }
};
diff --git a/sdm/include/private/hw_info_types.h b/sdm/include/private/hw_info_types.h
index ab69041..3b668b8 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -27,6 +27,7 @@
#include <stdint.h>
#include <core/display_interface.h>
+#include <core/core_interface.h>
namespace sdm {
@@ -65,6 +66,12 @@
kPortEDP,
};
+struct HWDynBwLimitInfo {
+ uint32_t cur_mode = kBwDefault;
+ uint32_t total_bw_limit[kBwModeMax] = { 0 };
+ uint32_t pipe_bw_limit[kBwModeMax] = { 0 };
+};
+
struct HWResourceInfo {
uint32_t hw_version = 0;
uint32_t hw_revision = 0;
@@ -102,6 +109,8 @@
bool has_non_scalar_rgb = false;
bool is_src_split = false;
bool perf_calc = false;
+ bool has_dyn_bw_support = false;
+ HWDynBwLimitInfo dyn_bw_info;
void Reset() { *this = HWResourceInfo(); }
};
diff --git a/sdm/include/private/resource_interface.h b/sdm/include/private/resource_interface.h
index 260bcf4..9a5aaea 100644
--- a/sdm/include/private/resource_interface.h
+++ b/sdm/include/private/resource_interface.h
@@ -51,6 +51,7 @@
bool is_top) = 0;
virtual DisplayError ValidateCursorPosition(Handle display_ctx, HWLayers *hw_layers,
int x, int y) = 0;
+ virtual DisplayError SetMaxBandwidthMode(HWBwModes mode) = 0;
protected:
virtual ~ResourceInterface() { }
diff --git a/sdm/libs/core/comp_manager.cpp b/sdm/libs/core/comp_manager.cpp
index 2c64875..c08b413 100644
--- a/sdm/libs/core/comp_manager.cpp
+++ b/sdm/libs/core/comp_manager.cpp
@@ -437,6 +437,14 @@
return supported;
}
+DisplayError CompManager::SetMaxBandwidthMode(HWBwModes mode) {
+ if ((hw_res_info_.has_dyn_bw_support == false) || (mode >= kBwModeMax)) {
+ return kErrorNotSupported;
+ }
+
+ return resource_intf_->SetMaxBandwidthMode(mode);
+}
+
bool CompManager::CanSetIdleTimeout(Handle display_ctx) {
DisplayCompositionContext *display_comp_ctx =
reinterpret_cast<DisplayCompositionContext *>(display_ctx);
diff --git a/sdm/libs/core/comp_manager.h b/sdm/libs/core/comp_manager.h
index a6b1432..daef25e 100644
--- a/sdm/libs/core/comp_manager.h
+++ b/sdm/libs/core/comp_manager.h
@@ -60,6 +60,7 @@
DisplayError ValidateCursorPosition(Handle display_ctx, HWLayers *hw_layers, int x, int y);
bool SupportLayerAsCursor(Handle display_ctx, HWLayers *hw_layers);
bool CanSetIdleTimeout(Handle display_ctx);
+ DisplayError SetMaxBandwidthMode(HWBwModes mode);
// DumpImpl method
virtual void AppendDump(char *buffer, uint32_t length);
diff --git a/sdm/libs/core/core_impl.cpp b/sdm/libs/core/core_impl.cpp
index 6a3ba1a..85ad2ff 100644
--- a/sdm/libs/core/core_impl.cpp
+++ b/sdm/libs/core/core_impl.cpp
@@ -206,5 +206,11 @@
return kErrorNone;
}
+DisplayError CoreImpl::SetMaxBandwidthMode(HWBwModes mode) {
+ SCOPE_LOCK(locker_);
+
+ return comp_mgr_.SetMaxBandwidthMode(mode);
+}
+
} // namespace sdm
diff --git a/sdm/libs/core/core_impl.h b/sdm/libs/core/core_impl.h
index c186754..06ca3d9 100644
--- a/sdm/libs/core/core_impl.h
+++ b/sdm/libs/core/core_impl.h
@@ -57,6 +57,7 @@
virtual DisplayError CreateDisplay(DisplayType type, DisplayEventHandler *event_handler,
DisplayInterface **intf);
virtual DisplayError DestroyDisplay(DisplayInterface *intf);
+ virtual DisplayError SetMaxBandwidthMode(HWBwModes mode);
protected:
Locker locker_;
diff --git a/sdm/libs/core/fb/hw_info.cpp b/sdm/libs/core/fb/hw_info.cpp
index b9a6669..e163f9a 100644
--- a/sdm/libs/core/fb/hw_info.cpp
+++ b/sdm/libs/core/fb/hw_info.cpp
@@ -76,6 +76,61 @@
return kErrorNone;
}
+DisplayError HWInfo::GetDynamicBWLimits(HWResourceInfo *hw_resource) {
+ const char *bw_info_node = "/sys/devices/virtual/graphics/fb0/mdp/bw_mode_bitmap";
+ FILE *fileptr = NULL;
+ uint32_t token_count = 0;
+ const uint32_t max_count = kBwModeMax;
+ char *tokens[max_count] = { NULL };
+ fileptr = Sys::fopen_(bw_info_node, "r");
+
+ if (!fileptr) {
+ DLOGE("File '%s' not found", bw_info_node);
+ return kErrorHardware;
+ }
+
+ HWDynBwLimitInfo* bw_info = &hw_resource->dyn_bw_info;
+ for (int index = 0; index < kBwModeMax; index++) {
+ bw_info->total_bw_limit[index] = hw_resource->max_bandwidth_low;
+ bw_info->pipe_bw_limit[index] = hw_resource->max_pipe_bw;
+ }
+
+ char *stringbuffer = reinterpret_cast<char *>(malloc(kMaxStringLength));
+ if (stringbuffer == NULL) {
+ DLOGE("Failed to allocate stringbuffer");
+ return kErrorMemory;
+ }
+
+ size_t len = kMaxStringLength;
+ ssize_t read;
+ char *line = stringbuffer;
+ while ((read = Sys::getline_(&line, &len, fileptr)) != -1) {
+ if (!ParseLine(line, tokens, max_count, &token_count)) {
+ if (!strncmp(tokens[0], "default_pipe", strlen("default_pipe"))) {
+ bw_info->pipe_bw_limit[kBwDefault] = UINT32(atoi(tokens[1]));
+ } else if (!strncmp(tokens[0], "camera_pipe", strlen("camera_pipe"))) {
+ bw_info->pipe_bw_limit[kBwCamera] = UINT32(atoi(tokens[1]));
+ } else if (!strncmp(tokens[0], "vflip_pipe", strlen("vflip_pipe"))) {
+ bw_info->pipe_bw_limit[kBwVFlip] = UINT32(atoi(tokens[1]));
+ } else if (!strncmp(tokens[0], "hflip_pipe", strlen("hflip_pipe"))) {
+ bw_info->pipe_bw_limit[kBwHFlip] = UINT32(atoi(tokens[1]));
+ } else if (!strncmp(tokens[0], "default", strlen("default"))) {
+ bw_info->total_bw_limit[kBwDefault] = UINT32(atoi(tokens[1]));
+ } else if (!strncmp(tokens[0], "camera", strlen("camera"))) {
+ bw_info->total_bw_limit[kBwCamera] = UINT32(atoi(tokens[1]));
+ } else if (!strncmp(tokens[0], "vflip", strlen("vflip"))) {
+ bw_info->total_bw_limit[kBwVFlip] = UINT32(atoi(tokens[1]));
+ } else if (!strncmp(tokens[0], "hflip", strlen("hflip"))) {
+ bw_info->total_bw_limit[kBwHFlip] = UINT32(atoi(tokens[1]));
+ }
+ }
+ }
+ free(stringbuffer);
+ Sys::fclose_(fileptr);
+
+ return kErrorNone;
+}
+
DisplayError HWInfo::GetHWResourceInfo(HWResourceInfo *hw_resource) {
if (!hw_resource) {
DLOGE("HWResourceInfo pointer in invalid.");
@@ -83,15 +138,22 @@
}
const char *fb_path = "/sys/devices/virtual/graphics/fb";
FILE *fileptr = NULL;
- char stringbuffer[kMaxStringLength];
uint32_t token_count = 0;
const uint32_t max_count = 10;
char *tokens[max_count] = { NULL };
- snprintf(stringbuffer , sizeof(stringbuffer), "%s%d/mdp/caps", fb_path, kHWCapabilitiesNode);
+ char *stringbuffer = reinterpret_cast<char *>(malloc(kMaxStringLength));
+
+ if (stringbuffer == NULL) {
+ DLOGE("Failed to allocate stringbuffer");
+ return kErrorMemory;
+ }
+
+ snprintf(stringbuffer , kMaxStringLength, "%s%d/mdp/caps", fb_path, kHWCapabilitiesNode);
fileptr = Sys::fopen_(stringbuffer, "r");
if (!fileptr) {
DLOGE("File '%s' not found", stringbuffer);
+ free(stringbuffer);
return kErrorHardware;
}
@@ -160,6 +222,8 @@
hw_resource->has_non_scalar_rgb = true;
} else if (!strncmp(tokens[i], "perf_calc", strlen("perf_calc"))) {
hw_resource->perf_calc = true;
+ } else if (!strncmp(tokens[i], "dynamic_bw_limit", strlen("dynamic_bw_limit"))) {
+ hw_resource->has_dyn_bw_support = true;
}
}
}
@@ -185,11 +249,12 @@
hw_resource->linear_factor, hw_resource->scale_factor, hw_resource->extra_fudge_factor);
const char *rotator_caps_path = "/sys/devices/virtual/rotator/mdss_rotator/caps";
- snprintf(stringbuffer , sizeof(stringbuffer), "%s", rotator_caps_path);
+ snprintf(stringbuffer , kMaxStringLength, "%s", rotator_caps_path);
fileptr = Sys::fopen_(stringbuffer, "r");
if (!fileptr) {
DLOGW("File '%s' not found", stringbuffer);
+ free(stringbuffer);
return kErrorNone;
}
@@ -203,11 +268,27 @@
}
}
+ free(stringbuffer);
Sys::fclose_(fileptr);
DLOGI("ROTATOR = %d, Rotator Downscale = %d", hw_resource->num_rotator,
hw_resource->has_rotator_downscale);
+ if (hw_resource->has_dyn_bw_support) {
+ DisplayError ret = GetDynamicBWLimits(hw_resource);
+ if (ret != kErrorNone) {
+ DLOGE("Failed to read dynamic band width info");
+ return ret;
+ }
+
+ DLOGI("Has Support for multiple bw limits shown below");
+ for (int index = 0; index < kBwModeMax; index++) {
+ DLOGI("Mode-index=%d total_bw_limit=%d and pipe_bw_limit=%d",
+ index, hw_resource->dyn_bw_info.total_bw_limit[index],
+ hw_resource->dyn_bw_info.pipe_bw_limit[index]);
+ }
+ }
+
return kErrorNone;
}
diff --git a/sdm/libs/core/fb/hw_info.h b/sdm/libs/core/fb/hw_info.h
index 350c6ff..9372734 100644
--- a/sdm/libs/core/fb/hw_info.h
+++ b/sdm/libs/core/fb/hw_info.h
@@ -45,6 +45,7 @@
static const int kHWCapabilitiesNode = 0;
static int ParseLine(char *input, char *tokens[], const uint32_t max_token, uint32_t *count);
+ DisplayError GetDynamicBWLimits(HWResourceInfo *hw_resource);
};
} // namespace sdm
diff --git a/sdm/libs/core/resource_default.cpp b/sdm/libs/core/resource_default.cpp
index aa6651f..ca73c36 100644
--- a/sdm/libs/core/resource_default.cpp
+++ b/sdm/libs/core/resource_default.cpp
@@ -917,6 +917,10 @@
return kErrorNotSupported;
}
+DisplayError ResourceDefault::SetMaxBandwidthMode(HWBwModes mode) {
+ return kErrorNotSupported;
+}
+
bool ResourceDefault::IsUBWCFormat(LayerBufferFormat format) {
switch (format) {
case kFormatRGBA8888Ubwc:
diff --git a/sdm/libs/core/resource_default.h b/sdm/libs/core/resource_default.h
index ce7d78b..67bb0fd 100644
--- a/sdm/libs/core/resource_default.h
+++ b/sdm/libs/core/resource_default.h
@@ -53,6 +53,7 @@
bool rotate90, bool ubwc_tiled, bool use_rotator_downscale);
DisplayError ValidateCursorConfig(Handle display_ctx, const Layer& layer, bool is_top);
DisplayError ValidateCursorPosition(Handle display_ctx, HWLayers *hw_layers, int x, int y);
+ DisplayError SetMaxBandwidthMode(HWBwModes mode);
private:
enum PipeId {
diff --git a/sdm/libs/hwc/hwc_session.cpp b/sdm/libs/hwc/hwc_session.cpp
index dbd06a7..779b440 100644
--- a/sdm/libs/hwc/hwc_session.cpp
+++ b/sdm/libs/hwc/hwc_session.cpp
@@ -42,6 +42,7 @@
#include <gralloc_priv.h>
#include <display_config.h>
#include <utils/debug.h>
+#include <sync/sync.h>
#include "hwc_buffer_allocator.h"
#include "hwc_buffer_sync_handler.h"
@@ -74,7 +75,6 @@
namespace sdm {
Locker HWCSession::locker_;
-bool HWCSession::reset_panel_ = false;
static void Invalidate(const struct hwc_procs *procs) {
}
@@ -246,11 +246,15 @@
hwc_procs = hwc_session->hwc_procs_;
- if (reset_panel_) {
+ if (hwc_session->reset_panel_) {
DLOGW("panel is in bad state, resetting the panel");
hwc_session->ResetPanel();
}
+ if (hwc_session->need_invalidate_) {
+ hwc_procs->invalidate(hwc_procs);
+ }
+
hwc_session->HandleSecureDisplaySession(displays);
if (hwc_session->color_mgr_) {
@@ -361,6 +365,15 @@
}
}
+ if (hwc_session->new_bw_mode_) {
+ hwc_display_contents_1_t *content_list = displays[HWC_DISPLAY_PRIMARY];
+ hwc_session->new_bw_mode_ = false;
+ if (hwc_session->bw_mode_release_fd_ >= 0) {
+ close(hwc_session->bw_mode_release_fd_);
+ }
+ hwc_session->bw_mode_release_fd_ = dup(content_list->retireFenceFd);
+ }
+
// Return 0, else client will go into bad state
return 0;
}
@@ -678,6 +691,14 @@
status = GetVisibleDisplayRect(input_parcel, output_parcel);
break;
+ case qService::IQService::SET_CAMERA_STATUS:
+ status = SetDynamicBWForCamera(input_parcel, output_parcel);
+ break;
+
+ case qService::IQService::GET_BW_TRANSACTION_STATUS:
+ status = GetBWTransactionStatus(input_parcel, output_parcel);
+ break;
+
default:
DLOGW("QService command = %d is not supported", command);
return -EINVAL;
@@ -959,6 +980,41 @@
return 0;
}
+android::status_t HWCSession::SetDynamicBWForCamera(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel) {
+ DisplayError error = kErrorNone;
+ uint32_t camera_status = UINT32(input_parcel->readInt32());
+ HWBwModes mode = camera_status > 0 ? kBwCamera : kBwDefault;
+
+ // trigger invalidate to apply new bw caps.
+ hwc_procs_->invalidate(hwc_procs_);
+
+ error = core_intf_->SetMaxBandwidthMode(mode);
+ if (error != kErrorNone) {
+ return -EINVAL;
+ }
+
+ new_bw_mode_ = true;
+ need_invalidate_ = true;
+
+ return 0;
+}
+
+android::status_t HWCSession::GetBWTransactionStatus(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel) {
+ bool state = true;
+
+ if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+ if (sync_wait(bw_mode_release_fd_, 0) < 0) {
+ DLOGI("bw_transaction_release_fd is not yet signalled: err= %s", strerror(errno));
+ state = false;
+ }
+ output_parcel->writeInt32(state);
+ }
+
+ return 0;
+}
+
void HWCSession::SetFrameDumpConfig(const android::Parcel *input_parcel) {
uint32_t frame_dump_count = UINT32(input_parcel->readInt32());
uint32_t bit_mask_display_type = UINT32(input_parcel->readInt32());
diff --git a/sdm/libs/hwc/hwc_session.h b/sdm/libs/hwc/hwc_session.h
index 78c9894..455ea83 100644
--- a/sdm/libs/hwc/hwc_session.h
+++ b/sdm/libs/hwc/hwc_session.h
@@ -117,6 +117,10 @@
android::status_t GetVisibleDisplayRect(const android::Parcel *input_parcel,
android::Parcel *output_parcel);
+ android::status_t SetDynamicBWForCamera(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel);
+ android::status_t GetBWTransactionStatus(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel);
static Locker locker_;
CoreInterface *core_intf_ = NULL;
hwc_procs_t hwc_procs_default_;
@@ -128,9 +132,12 @@
HWCBufferAllocator *buffer_allocator_ = NULL;
HWCBufferSyncHandler *buffer_sync_handler_ = NULL;
HWCColorManager *color_mgr_ = NULL;
- static bool reset_panel_;
+ bool reset_panel_ = false;
bool secure_display_active_ = false;
bool external_pending_connect_ = false;
+ bool new_bw_mode_ = false;
+ bool need_invalidate_ = false;
+ int bw_mode_release_fd_ = -1;
};
} // namespace sdm