summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarry Wentland <harry.wentland@amd.com>2015-07-31 21:50:26 -0400
committerAlex Deucher <alexander.deucher@amd.com>2015-09-21 17:45:16 -0400
commit3fc35e593d6e761cfce8efb2f3a20161a64e6a1b (patch)
tree930879febebb08b8c1b4cb471ffaa040a065b26d
parent73f546c938cf2b0e0ac047d1ffbde2151269ae21 (diff)
amd/dal: Mode Manager
The mode manager implements mode enumeration. It maintains a list of render modes for all connected displays. For each display mode manager fetches the list of timings from Display Capability Service (DCS). For each requested video network topology, Mode Manager will enumerate valid combinations of render modes and timings. SW Layer /===============================================================\ | Timing Mode Asic | | Service Manager Capability | | | | Display Display Link Adapter | | Path Capability Service Service | | Service | |---------------------------------------------------------------| | GPIO IRQ I2cAux HW BIOS | | Service Manager Sequencer Parser | | | | Connector Encoder Audio GPU Controller | \===============================================================/ HW Layer Signed-off-by: Harry Wentland <harry.wentland@amd.com>
-rw-r--r--drivers/gpu/drm/amd/dal/Makefile2
-rw-r--r--drivers/gpu/drm/amd/dal/include/mode_manager_interface.h110
-rw-r--r--drivers/gpu/drm/amd/dal/include/mode_manager_types.h142
-rw-r--r--drivers/gpu/drm/amd/dal/include/mode_query_interface.h93
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/Makefile16
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/best_view.c1291
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/best_view.h101
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/candidate_list.c128
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/candidate_list.h71
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/cofunctional_mode_query_validator.c136
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/cofunctional_mode_query_validator.h47
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/cofunctional_mode_validator.c136
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/cofunctional_mode_validator.h82
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/display_view_solution_container.c502
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/display_view_solution_container.h120
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/mode_manager.c812
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/mode_manager_types.c143
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/mode_query.c785
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/mode_query.h129
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/mode_query_allow_pan.c272
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/mode_query_allow_pan.h42
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/mode_query_no_pan.c303
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/mode_query_no_pan.h53
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/mode_query_set.c120
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/mode_query_set.h119
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/mode_query_tiled_display_preferred.c99
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/mode_query_tiled_display_preferred.h44
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/solution.c135
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/solution.h180
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/view_solution.c119
-rw-r--r--drivers/gpu/drm/amd/dal/mode_manager/view_solution.h154
31 files changed, 6485 insertions, 1 deletions
diff --git a/drivers/gpu/drm/amd/dal/Makefile b/drivers/gpu/drm/amd/dal/Makefile
index b1539026e723..92f0cee9bba7 100644
--- a/drivers/gpu/drm/amd/dal/Makefile
+++ b/drivers/gpu/drm/amd/dal/Makefile
@@ -9,7 +9,7 @@ subdir-ccflags-y += -I$(AMDDALPATH)/ -I$(AMDDALPATH)/include -DDAL_CZ_BRINGUP
DAL_LIBS = adapter amdgpu_dm audio asic_capability basics bios connector \
controller dcs display_path encoder gpio gpu hw_sequencer i2caux irq \
- link_service timing_service
+ link_service mode_manager timing_service
AMD_DAL = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DAL_PATH)/,$(DAL_LIBS)))
diff --git a/drivers/gpu/drm/amd/dal/include/mode_manager_interface.h b/drivers/gpu/drm/amd/dal/include/mode_manager_interface.h
new file mode 100644
index 000000000000..491a4f5d3d2a
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/include/mode_manager_interface.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DAL_MODE_MANAGER_INTEFACE_H__
+#define __DAL_MODE_MANAGER_INTEFACE_H__
+
+#include "mode_query_interface.h"
+#include "mode_manager_types.h"
+
+struct mode_timing_list;
+
+struct mode_manager;
+struct mode_manager_init_data {
+ const struct default_mode_list *default_modes;
+ struct adapter_service *as;
+ struct dal_context *dal_context;
+};
+
+struct mode_manager *dal_mode_manager_create(
+ const struct mode_manager_init_data *init_data);
+
+void dal_mode_manager_destroy(struct mode_manager **mm);
+
+uint32_t dal_mode_manager_get_supported_pixel_format(
+ const struct mode_manager *mm);
+
+void dal_mode_manager_set_supported_pixel_format(
+ struct mode_manager *mm,
+ uint32_t mask);
+
+struct bestview_options dal_mode_manager_get_default_bestview_options(
+ struct mode_manager *mm,
+ uint32_t display_index);
+
+struct bestview_options dal_mode_manager_get_bestview_options(
+ struct mode_manager *mode_mgr,
+ uint32_t display_index);
+
+void dal_mode_manager_set_bestview_options(
+ struct mode_manager *mode_mgr,
+ uint32_t display_index,
+ const struct bestview_options *bv_options,
+ bool rebuild_best_view,
+ struct mode_timing_list *mtl);
+
+/* Updates the cached render view table
+ * associated with given DisplayPath accordingly
+ */
+bool dal_mode_manager_update_disp_path_func_view_tbl(
+ struct mode_manager *mode_mgr,
+ uint32_t display_index,
+ struct mode_timing_list *mtl);
+
+/* generate all supported render modes
+ * and the corresponding cofunctional output mode set
+ * according to the given mode query parameter*/
+struct topology;
+struct mode_query *dal_mode_manager_create_mode_query(
+ struct mode_manager *mm,
+ const struct topology *topology,
+ const enum query_option query_option);
+
+/* Fills passed PathModeSet with the pathModes
+ * returned from querying specific mode
+ * Fallback options in this order:
+ * 1. Try interlaced refresh rate (if interlaced wasn't requested)
+ * 2. Try any refresh rate
+ * Returns true if PathModeSet for requested mode was found, false otherwise
+ * Updates renderMode + refreshRate if due to fallback found mode is different*/
+bool dal_mode_manager_retreive_path_mode_set(
+ struct mode_manager *mode_mgr,
+ struct path_mode_set *path_mode_set,
+ struct render_mode *render_mode,
+ struct refresh_rate *refresh_rate,
+ const struct topology *topology,
+ enum query_option query_option,
+ bool allow_fallback);
+
+bool dal_mode_manager_are_mode_queries_cofunctional(
+ const struct mode_manager *mode_mgr,
+ struct mode_query *ap_mode_queries,
+ uint32_t count);
+
+void dal_mode_manager_set_ds_dispatch(
+ struct mode_manager *mm,
+ struct ds_dispatch *ds_dispatch);
+
+#endif /* __DAL_MODE_MANAGER_INTEFACE_H__ */
diff --git a/drivers/gpu/drm/amd/dal/include/mode_manager_types.h b/drivers/gpu/drm/amd/dal/include/mode_manager_types.h
new file mode 100644
index 000000000000..b7208d80a009
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/include/mode_manager_types.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DAL_MODE_MANAGER_TYPES_H__
+#define __DAL_MODE_MANAGER_TYPES_H__
+
+#include "timing_service_types.h"
+#include "set_mode_interface.h"
+#include "bit_set.h"
+
+struct pixel_format_support {
+ bool INDEX8:1;
+ bool RGB565:1;
+ bool ARGB8888:1;
+ bool ARGB2101010:1;
+ bool ARGB2101010_XRBIAS:1;
+ bool FP16:1;
+};
+
+struct render_mode {
+ struct view view;
+ enum pixel_format pixel_format;
+};
+
+struct refresh_rate {
+ uint32_t field_rate;
+ bool INTERLACED:1;
+ bool VIDEO_OPTIMIZED_RATE:1;
+};
+
+struct stereo_3d_view {
+ enum view_3d_format view_3d_format;
+ union {
+ uint32_t raw;
+ struct /*stereo_3d_view_flags*/
+ {
+ bool SINGLE_FRAME_SW_PACKED:1;
+ bool EXCLUSIVE_3D:1;
+ } bits;
+ } flags;
+};
+
+enum solution_importance {
+ SOLUTION_IMPORTANCE_PREFERRED = 1,
+ /* Means we want to use this solution
+ * even in wide topology configurations*/
+ SOLUTION_IMPORTANCE_SAFE,
+ SOLUTION_IMPORTANCE_UNSAFE,
+ SOLUTION_IMPORTANCE_DEFAULT
+ /* Temporary state , means Solution object
+ * should define importance by itself
+ */
+};
+
+struct solution {
+ const struct mode_timing *mode_timing;
+ enum solution_importance importance;
+ bool is_custom_mode;
+ uint32_t scl_support[NUM_PIXEL_FORMATS];
+ /* bit vector of the scaling that can be supported on the timing */
+ uint32_t scl_support_guaranteed[NUM_PIXEL_FORMATS];
+ /* subset of m_sclSupport that can be guaranteed supported */
+};
+
+static inline void stereo_3d_view_reset(struct stereo_3d_view *stereo_3d_view)
+{
+ stereo_3d_view->view_3d_format = VIEW_3D_FORMAT_NONE;
+ stereo_3d_view->flags.raw = 0;
+}
+
+bool dal_refresh_rate_is_equal(
+ const struct refresh_rate *lhs,
+ const struct refresh_rate *rhs);
+
+bool dal_refresh_rate_less_than(
+ const struct refresh_rate *lhs,
+ const struct refresh_rate *rhs);
+
+void refresh_rate_from_mode_info(
+ struct refresh_rate *,
+ const struct mode_info *);
+bool dal_solution_less_than(const void *lhs, const void *rhs);
+bool dal_view_is_equal(const struct view *lhs, const struct view *rhs);
+
+struct pixel_format_list {
+ uint32_t set;
+ struct bit_set_iterator_32 iter;
+};
+
+void dal_pixel_format_list_reset_iterator(struct pixel_format_list *pfl);
+void dal_pixel_format_list_zero_iterator(struct pixel_format_list *pfl);
+
+void dal_pixel_format_list_construct(
+ struct pixel_format_list *pfl,
+ uint32_t mask);
+
+uint32_t dal_pixel_format_list_next(struct pixel_format_list *pfl);
+
+uint32_t dal_pixel_format_list_get_count(
+ const struct pixel_format_list *pfl);
+enum pixel_format dal_pixel_format_list_get_pixel_format(
+ const struct pixel_format_list *pfl);
+
+enum timing_select {
+ TIMING_SELECT_DEFAULT,
+ TIMING_SELECT_NATIVE_ONLY,
+ TIMING_SELECT_PRESERVE_ASPECT
+};
+
+struct bestview_options {
+ enum timing_select base_timing_select;
+ enum display_color_depth prefered_color_depth;
+ enum pixel_encoding prefered_pixel_encoding;
+ bool RESTRICT_HD_TIMING:1;
+ bool DISALLOW_CUSTOM_MODES_AS_BASE:1;
+ bool MAINTAIN_ASPECT_RATIO:1;
+ bool ENABLE_SCALING:1;
+};
+
+#endif /* __DAL_MODE_MANAGER_TYPES_H__ */
diff --git a/drivers/gpu/drm/amd/dal/include/mode_query_interface.h b/drivers/gpu/drm/amd/dal/include/mode_query_interface.h
new file mode 100644
index 000000000000..1d20e73ad85e
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/include/mode_query_interface.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DAL_MODE_QUERY_INTERFACE_H__
+#define __DAL_MODE_QUERY_INTERFACE_H__
+
+#include "include/set_mode_types.h"
+#include "include/mode_manager_types.h"
+
+enum query_option {
+ QUERY_OPTION_ALLOW_PAN,
+ QUERY_OPTION_ALLOW_PAN_NO_VIEW_RESTRICTION,
+ QUERY_OPTION_PAN_ON_LIMITED_RESOLUTION_DISP_PATH,
+ QUERY_OPTION_NO_PAN,
+ QUERY_OPTION_NO_PAN_NO_DISPLAY_VIEW_RESTRICTION,
+ QUERY_OPTION_3D_LIMITED_CANDIDATES,
+ QUERY_OPTION_TILED_DISPLAY_PREFERRED,
+ QUERY_OPTION_MAX,
+};
+
+struct topology {
+ uint32_t disp_path_num;
+ uint32_t display_index[MAX_COFUNC_PATH];
+};
+
+struct path_mode;
+struct mode_query;
+
+bool dal_mode_query_pin_path_mode(
+ struct mode_query *mq,
+ const struct path_mode *path_mode);
+
+const struct render_mode *dal_mode_query_get_current_render_mode(
+ const struct mode_query *mq);
+
+const struct stereo_3d_view *dal_mode_query_get_current_3d_view(
+ const struct mode_query *mq);
+
+const struct refresh_rate *dal_mode_query_get_current_refresh_rate(
+ const struct mode_query *mq);
+
+const struct path_mode_set *dal_mode_query_get_current_path_mode_set(
+ const struct mode_query *mq);
+
+bool dal_mode_query_select_first(struct mode_query *mq);
+bool dal_mode_query_select_next_render_mode(struct mode_query *mq);
+
+bool dal_mode_query_select_render_mode(struct mode_query *mq,
+ const struct render_mode *render_mode);
+
+bool dal_mode_query_select_next_view_3d_format(struct mode_query *mq);
+bool dal_mode_query_select_view_3d_format(
+ struct mode_query *mq,
+ enum view_3d_format format);
+
+bool dal_mode_query_select_refresh_rate(struct mode_query *mq,
+ const struct refresh_rate *refresh_rate);
+
+bool dal_mode_query_select_refresh_rate_ex(struct mode_query *mq,
+ uint32_t refresh_rate,
+ bool interlaced);
+
+bool dal_mode_query_select_next_scaling(struct mode_query *mq);
+
+bool dal_mode_query_select_next_refresh_rate(struct mode_query *mq);
+
+bool dal_mode_query_base_select_next_scaling(struct mode_query *mq);
+
+void dal_mode_query_destroy(struct mode_query **mq);
+
+#endif /* __DAL_MODE_QUERY_INTERFACE_H__ */
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/Makefile b/drivers/gpu/drm/amd/dal/mode_manager/Makefile
new file mode 100644
index 000000000000..131b166f1efd
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/Makefile
@@ -0,0 +1,16 @@
+#
+# Makefile for the 'mode' sub-component of DAL.
+# It provides the mode management services for the driver.
+
+BEST_VIEW = best_view.o candidate_list.o solution.o
+
+MODE_QUERY = mode_query.o mode_query_set.o mode_query_allow_pan.o \
+ mode_query_no_pan.o mode_query_tiled_display_preferred.o
+
+MODE_MGR = $(BEST_VIEW) $(MODE_QUERY) cofunctional_mode_validator.o \
+ display_view_solution_container.o mode_manager.o \
+ mode_manager_types.o view_solution.o cofunctional_mode_query_validator.o
+
+AMD_DAL_MODE = $(addprefix $(AMDDALPATH)/mode_manager/,$(MODE_MGR))
+
+AMD_DAL_FILES += $(AMD_DAL_MODE)
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/best_view.c b/drivers/gpu/drm/amd/dal/mode_manager/best_view.c
new file mode 100644
index 000000000000..4d1499738064
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/best_view.c
@@ -0,0 +1,1291 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dal_services.h"
+#include "include/mode_manager_types.h"
+#include "include/timing_service_interface.h"
+#include "include/mode_timing_list_interface.h"
+#include "include/logger_interface.h"
+#include "best_view.h"
+#include "solution.h"
+
+static const struct mode_info best_view_ce_mode_only_fid9204hp_ce_modes[] = {
+/* 480p 60, 59.94*/
+{ 720, 480, 60, TIMING_STANDARD_CEA861, TIMING_SOURCE_UNDEFINED,
+ { 0, 0, 0, 0, 1 } },
+{ 720, 480, 60, TIMING_STANDARD_CEA861, TIMING_SOURCE_UNDEFINED,
+ { 0, 0, 0, 0, 0 } },
+/* 576p 50*/
+{ 720, 576, 50, TIMING_STANDARD_CEA861, TIMING_SOURCE_UNDEFINED,
+ { 0, 0, 0, 0, 0 } },
+/* 720p 60, 50*/
+{ 1280, 720, 50, TIMING_STANDARD_CEA861, TIMING_SOURCE_UNDEFINED,
+ { 0, 0, 0, 0, 0 } },
+{ 1280, 720, 60, TIMING_STANDARD_CEA861, TIMING_SOURCE_UNDEFINED,
+ { 0, 0, 0, 0, 0 } },
+/*1080p 24*/
+{ 1920, 1080, 24, TIMING_STANDARD_CEA861, TIMING_SOURCE_UNDEFINED,
+ { 0, 0, 0, 0, 0 } },
+/*1080i 60, 50*/
+{ 1920, 1080, 50, TIMING_STANDARD_CEA861, TIMING_SOURCE_UNDEFINED,
+ { 1, 0, 0, 0, 0 } },
+{ 1920, 1080, 60, TIMING_STANDARD_CEA861, TIMING_SOURCE_UNDEFINED,
+ { 1, 0, 0, 0, 0 } },
+/*1080p 60, 50*/
+{ 1920, 1080, 50, TIMING_STANDARD_CEA861, TIMING_SOURCE_UNDEFINED,
+ { 0, 0, 0, 0, 0 } },
+{ 1920, 1080, 60, TIMING_STANDARD_CEA861, TIMING_SOURCE_UNDEFINED,
+ { 0, 0, 0, 0, 0 } }, };
+
+#define NUM_FID9204HP_CE_MODES \
+ ARRAY_SIZE(best_view_ce_mode_only_fid9204hp_ce_modes)
+
+static void print_bw_to_log(const struct best_view *bv, const char *bv_type);
+
+static bool best_view_construct(
+ struct best_view *bv,
+ const struct best_view_init_data *init_data)
+{
+ if (init_data != NULL && init_data->set_mode_params != NULL)
+ bv->set_mode_params = init_data->set_mode_params;
+ else
+ return false;
+
+ if (!dal_candidate_list_construct(&bv->identity_candidates))
+ return false;
+
+ if (!dal_candidate_list_construct(&bv->scaled_candidates))
+ goto destruct_identity;
+
+ if (!dal_candidate_list_construct(&bv->preferred_candidates))
+ goto destruct_scaled;
+
+ bv->display_index = init_data->display_index;
+
+ dal_memmove(
+ &bv->flags,
+ &init_data->flags,
+ sizeof(union best_view_flags));
+
+ dal_memmove(
+ &bv->options,
+ &init_data->bv_option,
+ sizeof(struct bestview_options));
+ return true;
+
+destruct_scaled:
+ dal_candidate_list_destruct(&bv->scaled_candidates);
+
+destruct_identity:
+ dal_candidate_list_destruct(&bv->identity_candidates);
+ return false;
+}
+
+static bool is_candidate_multiple_refresh_rate(
+ const struct mode_timing *mode_timing)
+{
+ if (mode_timing->mode_info.flags.INTERLACE)
+ return false;
+
+ switch (mode_timing->mode_info.timing_source) {
+ case TIMING_SOURCE_EDID_CEA_SVD_3D:
+ case TIMING_SOURCE_EDID_CEA_SVD:
+ case TIMING_SOURCE_USER_OVERRIDE:
+ case TIMING_SOURCE_USER_FORCED:
+ case TIMING_SOURCE_VBIOS:
+ /* if some detailed timings with a specified refresh rate
+ * are in EDID basic block, we will see other modes
+ * in stdTimings have that same additional refresh rate. */
+ case TIMING_SOURCE_EDID_DETAILED:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool is_timing_priority_higher(
+ const struct best_view *bv,
+ const struct mode_timing *lhs,
+ const struct mode_timing *rhs)
+{
+ uint32_t distance_lhs, distance_rhs;
+
+ if (rhs == NULL || lhs == NULL) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+
+ /* First check 3D preference
+ *(i.e. 3D preference enabled + source match
+ *(i.e. + new timing is 3D + old timing is 2D)*/
+ if (bv->flags.bits.PREFER_3D_TIMING &&
+ lhs->mode_info.timing_source <= rhs->mode_info.timing_source) {
+ bool timing_3d_pref_rhs =
+ rhs->crtc_timing.timing_3d_format !=
+ TIMING_3D_FORMAT_NONE ||
+ rhs->crtc_timing.flags.STEREO_3D_PREFERENCE;
+ bool timing_3d_pref_lhs =
+ lhs->crtc_timing.timing_3d_format !=
+ TIMING_3D_FORMAT_NONE ||
+ lhs->crtc_timing.flags.STEREO_3D_PREFERENCE;
+
+ if (timing_3d_pref_lhs && !timing_3d_pref_rhs)
+ return true;
+ }
+
+ /* Next check for best pixel encoding (if preferred specified)*/
+ if (bv->options.prefered_pixel_encoding != PIXEL_ENCODING_UNDEFINED) {
+ distance_lhs = abs(lhs->crtc_timing.pixel_encoding -
+ bv->options.prefered_pixel_encoding);
+ distance_rhs = abs(rhs->crtc_timing.pixel_encoding -
+ bv->options.prefered_pixel_encoding);
+
+ /* if the new mode timing is closer to the pixel encoding
+ * then it is higher priority*/
+ if (distance_lhs != distance_rhs)
+ return distance_lhs < distance_rhs;
+ }
+
+ /* Next check for best color depth (if preferred specified)*/
+ if (bv->options.prefered_color_depth
+ != DISPLAY_COLOR_DEPTH_UNDEFINED) {
+ distance_lhs = abs(lhs->crtc_timing.display_color_depth -
+ bv->options.prefered_color_depth);
+ distance_rhs = abs(rhs->crtc_timing.display_color_depth -
+ bv->options.prefered_color_depth);
+
+ if (distance_lhs != distance_rhs)
+ return distance_lhs < distance_rhs;
+ }
+
+ if (lhs->mode_info.flags.PREFERRED >
+ rhs->mode_info.flags.PREFERRED)
+ return true;
+
+ else if (lhs->mode_info.flags.PREFERRED <
+ rhs->mode_info.flags.PREFERRED)
+ return false;
+
+
+ /* Finally check for best timing source
+ * (timing source enum lower value has higher priority) */
+ return lhs->mode_info.timing_source < rhs->mode_info.timing_source;
+}
+
+void update_solution_support_matrix_for_scaling_trans(
+ struct best_view *bv,
+ struct solution *solution,
+ enum scaling_transformation st,
+ struct set_mode_params *set_mode_params)
+{
+ enum pixel_format pf;
+ bool guaranteed, supported;
+
+ dal_set_mode_params_update_scaling_on_path(
+ bv->set_mode_params,
+ bv->display_index,
+ st);
+
+ /* We need to validate every pixel format,
+ * some of them may be not supported regardless bandwidth consumption.*/
+ for (pf = PIXEL_FORMAT_GRPH_END;
+ pf >= PIXEL_FORMAT_GRPH_BEGIN; pf >>= 1) {
+
+ dal_set_mode_params_update_pixel_format_on_path(
+ bv->set_mode_params,
+ bv->display_index,
+ pf);
+
+ /* if PathMode is guaranteed, it has to be supported */
+ guaranteed = dal_set_mode_params_is_path_mode_set_guaranteed(
+ bv->set_mode_params);
+ supported = guaranteed ||
+ dal_set_mode_params_is_path_mode_set_supported(
+ bv->set_mode_params);
+
+ dal_solution_set_support_matrix(
+ solution,
+ pf,
+ st,
+ supported,
+ guaranteed);
+
+ /* code below is for static gathering purpose */
+ if (supported) {
+ bv->supported_path_mode_cnt++;
+ if (!guaranteed)
+ bv->non_guaranteed_path_mode_cnt++;
+ }
+ }
+}
+
+static bool add_output_mode(
+ struct best_view *bv,
+ const struct view *vw,
+ const struct mtp mtp,
+ const struct scaling_support scaling_support,
+ enum solution_importance importance,
+ struct solution_set *target_solution_list)
+{
+ struct solution *solution;
+ bool ret = false;
+
+ solution = dal_alloc(sizeof(struct solution));
+
+ if (!solution) {
+ ret = false;
+ goto cleanup;
+ }
+
+ if (mtp.value == NULL) {
+ ret = false;
+ goto cleanup;
+ }
+
+ if ((vw->width > mtp.value->mode_info.pixel_width ||
+ vw->height > mtp.value->mode_info.pixel_height) &&
+ /* allow downscaling for TV view up to 1024x768 */
+ !(mtp.value->mode_info.timing_source == TIMING_SOURCE_TV &&
+ vw->width <= 1024 &&
+ vw->height <= 768)) {
+ ret = false;
+ goto cleanup;
+ }
+
+ dal_solution_construct(solution, mtp.value, importance);
+
+ /* View and Timing used for validation is known, update here.
+ * At his point we do not care about 3D format validation
+ * since TS already guaranteed static 3D validation
+ * for single path topology */
+ if (!dal_set_mode_params_update_view_on_path(
+ bv->set_mode_params,
+ bv->display_index,
+ vw)) {
+ ret = false;
+ goto cleanup;
+ }
+ if (!dal_set_mode_params_update_mode_timing_on_path(
+ bv->set_mode_params,
+ bv->display_index,
+ mtp.value,
+ VIEW_3D_FORMAT_NONE)) {
+ ret = false;
+ goto cleanup;
+ }
+
+ /*
+ * solution object will update scaling according to input parameter
+ * and enumerate all possible pixelFormat to validate
+ * solution will then cache the validation results in support matrix
+ */
+ if (scaling_support.IDENTITY) {
+ update_solution_support_matrix_for_scaling_trans(
+ bv,
+ solution,
+ SCALING_TRANSFORMATION_IDENTITY,
+ bv->set_mode_params);
+ }
+
+ if (scaling_support.CENTER_TIMING)
+ update_solution_support_matrix_for_scaling_trans(
+ bv,
+ solution,
+ SCALING_TRANSFORMATION_CENTER_TIMING,
+ bv->set_mode_params);
+
+ if (scaling_support.FULL_SCREEN_SCALE)
+ update_solution_support_matrix_for_scaling_trans(bv,
+ solution,
+ SCALING_TRANSFORMATION_FULL_SCREEN_SCALE,
+ bv->set_mode_params);
+
+ if (scaling_support.PRESERVE_ASPECT_RATIO_SCALE)
+ update_solution_support_matrix_for_scaling_trans(
+ bv,
+ solution,
+ SCALING_TRANSFORMATION_PRESERVE_ASPECT_RATIO_SCALE,
+ bv->set_mode_params);
+
+ if (!dal_solution_is_empty(solution)) {
+ if (!solution_set_insert(target_solution_list, solution))
+ BREAK_TO_DEBUGGER();
+ if (dal_solution_get_importance(solution) <=
+ SOLUTION_IMPORTANCE_SAFE) {
+ ret = true;
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ dal_free(solution);
+ return ret;
+}
+
+static bool add_timing_to_candidate_list_with_priority(
+ struct best_view *bv,
+ struct candidate_list *cl,
+ const struct mode_timing *mode_timing)
+{
+ uint32_t cl_size;
+ struct mtp last_mtp;
+ enum timing_3d_format last_mt_3d_fmt;
+ enum timing_3d_format new_mt_3d_fmt;
+
+ if (cl == NULL || mode_timing == NULL) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+
+ if (bv->options.RESTRICT_HD_TIMING &&
+ dal_timing_service_is_ce_hd_timing(mode_timing))
+ return false;
+
+ cl_size = dal_candidate_list_get_count(cl);
+ if (cl_size == 0) {
+ if (!dal_candidate_list_insert(cl, mode_timing)) {
+ dal_logger_write(bv->ctx->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_MODE_ENUM_BEST_VIEW_CANDIDATES,
+ "%s - Out of Memory\n", __func__);
+ return false;
+ }
+ }
+
+ last_mtp = dal_candidate_list_at_index(
+ cl,
+ dal_candidate_list_get_count(cl) - 1);
+
+ last_mt_3d_fmt = last_mtp.value->crtc_timing.flags.USE_IN_3D_VIEW_ONLY ?
+ last_mtp.value->crtc_timing.timing_3d_format :
+ TIMING_3D_FORMAT_NONE;
+
+ new_mt_3d_fmt = mode_timing->crtc_timing.flags.USE_IN_3D_VIEW_ONLY ?
+ mode_timing->crtc_timing.timing_3d_format :
+ TIMING_3D_FORMAT_NONE;
+
+ /* check for an identical mode (including 3D format)
+ * We allow in the list two timings with different 3D formats
+ * if this is actually same timing spawned by multiple 3D formats*/
+ if (last_mtp.value->mode_info.pixel_width ==
+ mode_timing->mode_info.pixel_width &&
+ last_mtp.value->mode_info.pixel_height ==
+ mode_timing->mode_info.pixel_height &&
+ last_mtp.value->mode_info.field_rate ==
+ mode_timing->mode_info.field_rate &&
+ last_mtp.value->mode_info.flags.INTERLACE ==
+ mode_timing->mode_info.flags.INTERLACE &&
+ last_mtp.value->mode_info.flags.VIDEO_OPTIMIZED_RATE ==
+ mode_timing->mode_info.flags.
+ VIDEO_OPTIMIZED_RATE &&
+ last_mt_3d_fmt == new_mt_3d_fmt) {
+ /* if the new mode timing matches
+ * the preferred pixel encoding then we want to add it */
+ if (is_timing_priority_higher(
+ bv, mode_timing, last_mtp.value)) {
+ /* remove the last added mode
+ * so we can add this new one*/
+ if (!dal_candidate_list_remove_at_index(cl, cl_size - 1)) {
+ BREAK_TO_DEBUGGER();
+ /*should never be here*/
+ return false;
+ }
+ } else
+ /* skip adding the same mode to the candidate list */
+ return false;
+ }
+
+ if (!dal_candidate_list_insert(cl, mode_timing)) {
+ dal_logger_write(bv->ctx->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_MODE_ENUM_BEST_VIEW_CANDIDATES,
+ "%s - Out of Memory\n", __func__);
+ return false;
+ }
+ return true;
+}
+
+static void best_view_destruct(struct best_view *bv)
+{
+ dal_candidate_list_destruct(&bv->identity_candidates);
+ dal_candidate_list_destruct(&bv->scaled_candidates);
+ dal_candidate_list_destruct(&bv->preferred_candidates);
+}
+
+static bool is_fid9204hp_ce_mode(const struct mode_info *mode_info)
+{
+ uint32_t i;
+ const struct mode_info *ce_mode_info;
+
+ for (i = 0; i < NUM_FID9204HP_CE_MODES; i++) {
+ ce_mode_info = &best_view_ce_mode_only_fid9204hp_ce_modes[i];
+ if ((mode_info->pixel_width == ce_mode_info->pixel_width) &&
+ mode_info->pixel_height == ce_mode_info->pixel_height &&
+ mode_info->field_rate == ce_mode_info->field_rate &&
+ mode_info->timing_standard ==
+ ce_mode_info->timing_standard &&
+ mode_info->flags.INTERLACE ==
+ ce_mode_info->flags.INTERLACE &&
+ mode_info->flags.VIDEO_OPTIMIZED_RATE ==
+ ce_mode_info->flags.VIDEO_OPTIMIZED_RATE)
+ return true;
+ }
+ return false;
+}
+
+
+static enum display_view_importance
+ best_view_ce_mode_only_get_view_importance_override
+ (const struct best_view *bv, const struct view *vw)
+{
+ uint32_t i;
+ const struct mode_info *ce_mode_info;
+
+ for (i = 0; i < NUM_FID9204HP_CE_MODES; i++) {
+ ce_mode_info = &best_view_ce_mode_only_fid9204hp_ce_modes[i];
+ if (vw->width == ce_mode_info->pixel_width &&
+ vw->height == ce_mode_info->pixel_height)
+ return DISPLAY_VIEW_IMPORTANCE_BESTVIEW_OVERRIDE;
+ }
+ return DISPLAY_VIEW_IMPORTANCE_NON_GUARANTEED;
+}
+
+static const struct best_biew_funcs best_view_ce_mode_only_funcs = {
+ .get_view_importance_override =
+ best_view_ce_mode_only_get_view_importance_override
+};
+
+static bool best_view_ce_mode_only_construct(
+ struct best_view *bv,
+ const struct best_view_init_data *init_data)
+{
+ uint32_t i;
+ uint32_t mtl_size;
+ const struct mode_timing *mt;
+
+ if (!best_view_construct(bv, init_data))
+ return false;
+ mtl_size = dal_mode_timing_list_get_count(init_data->mode_timing_list);
+ for (i = 0; i < mtl_size; i++) {
+ mt = dal_mode_timing_list_get_timing_at_index(
+ init_data->mode_timing_list, i);
+
+ if (is_fid9204hp_ce_mode(&mt->mode_info)) {
+ add_timing_to_candidate_list_with_priority(
+ bv,
+ &bv->identity_candidates,
+ mt);
+ add_timing_to_candidate_list_with_priority(
+ bv,
+ &bv->scaled_candidates,
+ mt);
+ add_timing_to_candidate_list_with_priority(
+ bv,
+ &bv->preferred_candidates,
+ mt);
+ }
+ }
+ bv->funcs = &best_view_ce_mode_only_funcs;
+ bv->mode_enum_override.
+ ALLOW_ONLY_BEST_VIEW_OVERRIDE_DISPLAY_VIEW = true;
+ bv->mode_enum_override.RESTRICT_ADAPTER_VIEW = true;
+ print_bw_to_log(bv, "CeModeOnly");
+ return true;
+}
+
+static inline bool is_custom_timing_source(enum timing_source ts)
+{
+ return ts == TIMING_SOURCE_CUSTOM || ts == TIMING_SOURCE_CUSTOM_BASE;
+}
+
+static enum display_view_importance get_view_importance_override(
+ const struct best_view *bv,
+ const struct view *view)
+{
+ return DISPLAY_VIEW_IMPORTANCE_NON_GUARANTEED;
+}
+
+static const struct best_biew_funcs best_view_default_funcs = {
+ .get_view_importance_override = get_view_importance_override
+};
+
+static bool best_view_default_construct(
+ struct best_view *bv,
+ struct best_view_init_data *bv_init_data)
+{
+ uint32_t i, mtl_size;
+ enum timing_support_method tsm;
+ const struct mode_timing *mt = NULL;
+ const struct mode_timing *preferred_mode = NULL;
+ const struct mode_timing *largest_mode = NULL;
+
+ if (bv_init_data == NULL ||
+ bv_init_data->mode_timing_list == NULL ||
+ !best_view_construct(bv, bv_init_data))
+ return false;
+
+ mtl_size = dal_mode_timing_list_get_count(
+ bv_init_data->mode_timing_list);
+ for (i = 0; i < mtl_size; i++) {
+ mt = dal_mode_timing_list_get_timing_at_index(
+ bv_init_data->mode_timing_list,
+ i);
+
+ if (preferred_mode == NULL && mt->mode_info.flags.PREFERRED)
+ preferred_mode = mt;
+
+ switch (mt->mode_info.timing_source) {
+ case TIMING_SOURCE_EDID_CEA_SVD_3D:
+ case TIMING_SOURCE_EDID_DETAILED:
+ case TIMING_SOURCE_EDID_ESTABLISHED:
+ case TIMING_SOURCE_EDID_STANDARD:
+ case TIMING_SOURCE_EDID_CEA_SVD:
+ case TIMING_SOURCE_EDID_CVT_3BYTE:
+ case TIMING_SOURCE_EDID_4BYTE:
+ /* choose largest mode from EDID,
+ * not from custom or forced */
+ largest_mode = mt;
+ break;
+ default:
+ break;
+ }
+
+ /* skip identical modes
+ * unless it is higher priority than current one */
+ add_timing_to_candidate_list_with_priority(
+ bv,
+ &bv->identity_candidates,
+ mt);
+ }
+
+ for (i = 0; i < mtl_size; i++) {
+ mt = dal_mode_timing_list_get_timing_at_index(
+ bv_init_data->mode_timing_list,
+ i);
+ tsm = dal_timing_service_get_timing_support_method(mt);
+
+ /*skip if custom mode is not allowed as base mode,
+ * parameter comes from CCC */
+ if (bv_init_data->bv_option.DISALLOW_CUSTOM_MODES_AS_BASE &&
+ is_custom_timing_source(
+ mt->mode_info.timing_source))
+ continue;
+
+ /*We don't allow any mode to be added
+ * to the scaled candidate list if its larger
+ * than the largest native mode.
+ * This is can happen in the case the user adds
+ * a forced HDTV mode and we end up scaling
+ * to that custom mode. */
+ if (largest_mode != NULL &&
+ (mt->mode_info.pixel_width >
+ largest_mode->mode_info.pixel_width ||
+ mt->mode_info.pixel_height >
+ largest_mode->mode_info.pixel_height) &&
+ (is_custom_timing_source(mt->mode_info.timing_source) ||
+ mt->mode_info.timing_source ==
+ TIMING_SOURCE_USER_FORCED))
+ continue;
+
+ /* while scanning the mode timing list,
+ * build up the preferred refresh rate list */
+ if (preferred_mode != NULL
+ && is_candidate_multiple_refresh_rate(mt)
+ && mt->mode_info.pixel_height ==
+ preferred_mode->mode_info.pixel_height
+ && mt->mode_info.pixel_width ==
+ preferred_mode->mode_info.pixel_width)
+ add_timing_to_candidate_list_with_priority(
+ bv,
+ &bv->preferred_candidates,
+ mt);
+
+ if (tsm == TIMING_SUPPORT_METHOD_EXPLICIT
+ || tsm == TIMING_SUPPORT_METHOD_NATIVE)
+ add_timing_to_candidate_list_with_priority(
+ bv,
+ &bv->scaled_candidates,
+ mt);
+ }
+
+
+ if (dal_candidate_list_get_count(&bv->scaled_candidates) == 0 &&
+ mt != NULL)
+ /* no native mode found in ModeTimingList,
+ * default to largest mode as native */
+ if (!dal_candidate_list_insert(
+ &bv->scaled_candidates,
+ mt)) {
+ BREAK_TO_DEBUGGER();
+ dal_logger_write(bv->ctx->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_MODE_ENUM_BEST_VIEW_CANDIDATES,
+ "%s - Out of Memory\n", __func__);
+ best_view_destruct(bv);
+ return false;
+ }
+
+ bv->funcs = &best_view_default_funcs;
+
+ print_bw_to_log(bv, "Default");
+ return true;
+}
+
+static bool best_view_gpu_scaling_construct(
+ struct best_view *bv,
+ struct best_view_init_data *bv_init_data)
+{
+ int32_t i;
+ uint32_t mtl_size;
+ const struct mode_timing *mt;
+ const struct mode_info *preferred_mode = NULL;
+ const struct mode_info *largest_native_mode = NULL;
+ const struct mode_info *largest_mode = NULL;
+
+ if (bv_init_data == NULL ||
+ bv_init_data->mode_timing_list == NULL ||
+ !best_view_construct(bv, bv_init_data))
+ return false;
+
+ bv->funcs = &best_view_default_funcs;
+
+ /* GPU scaling candidates:
+ * 1. Timing exactly matching preferred mode(paired with preferred mode)
+ * 2. All detailed timings with resolution matching preferred mode
+ * 2. Largest Native Timing (to make sure we do not miss big modes)
+ * 3. OS Forced Timing
+ * 4. User Forced Timing
+ * 5. Customized Timing
+ * 6. Largest Timing */
+
+ /* Find preferred mode and mode for largest native timing */
+ mtl_size = dal_mode_timing_list_get_count(
+ bv_init_data->mode_timing_list);
+ for (i = mtl_size;
+ i > 0 &&
+ (preferred_mode == NULL ||
+ largest_native_mode == NULL);
+ i--) {
+ mt = dal_mode_timing_list_get_timing_at_index(
+ bv_init_data->mode_timing_list,
+ i - 1);
+
+ if (preferred_mode == NULL && mt->mode_info.flags.PREFERRED)
+ preferred_mode = &mt->mode_info;
+
+ if (largest_native_mode == NULL && mt->mode_info.flags.NATIVE)
+ largest_native_mode = &mt->mode_info;
+
+ if (largest_mode == NULL) {
+ /* don't allow any of these to be the largest mode
+ * as it will not be added as a scaled candidate*/
+ if (mt->mode_info.timing_source ==
+ TIMING_SOURCE_USER_FORCED ||
+ mt->mode_info.timing_source ==
+ TIMING_SOURCE_OS_FORCED ||
+ mt->mode_info.timing_source ==
+ TIMING_SOURCE_CUSTOM ||
+ mt->mode_info.timing_source ==
+ TIMING_SOURCE_CUSTOM_BASE ||
+ mt->mode_info.timing_source ==
+ TIMING_SOURCE_DALINTERFACE_EXPLICIT ||
+ mt->mode_info.timing_source ==
+ TIMING_SOURCE_DALINTERFACE_IMPLICIT)
+ continue;
+ largest_mode = &mt->mode_info;
+ }
+ }
+
+ for (i = 0; i < mtl_size; i++) {
+ mt = dal_mode_timing_list_get_timing_at_index(
+ bv_init_data->mode_timing_list,
+ i);
+
+ /* Add timing exactly matching preferred mode
+ * (preferred mode can come not from detailed)*/
+ /* Add detailed timing with resolution matching preferred mode*/
+ if (mt->mode_info.flags.PREFERRED ||
+ (preferred_mode != NULL &&
+ preferred_mode->pixel_width ==
+ mt->mode_info.pixel_width &&
+ preferred_mode->pixel_height ==
+ mt->mode_info.pixel_height &&
+ (mt->mode_info.timing_source ==
+ TIMING_SOURCE_EDID_DETAILED ||
+ mt->mode_info.timing_source ==
+ TIMING_SOURCE_EDID_CEA_SVD_3D))) {
+ add_timing_to_candidate_list_with_priority(
+ bv,
+ &bv->identity_candidates,
+ mt);
+ add_timing_to_candidate_list_with_priority(
+ bv,
+ &bv->scaled_candidates,
+ mt);
+ add_timing_to_candidate_list_with_priority(
+ bv,
+ &bv->preferred_candidates,
+ mt);
+ } else if (largest_native_mode != NULL
+ && dal_mode_info_is_equal(
+ largest_native_mode,
+ &mt->mode_info)) {
+ /* Add largest native timing */
+ add_timing_to_candidate_list_with_priority(
+ bv,
+ &bv->identity_candidates,
+ mt);
+ add_timing_to_candidate_list_with_priority(
+ bv,
+ &bv->scaled_candidates,
+ mt);
+ if (is_candidate_multiple_refresh_rate(mt))
+ add_timing_to_candidate_list_with_priority(
+ bv,
+ &bv->preferred_candidates,
+ mt);
+ } else if (is_custom_timing_source(mt->mode_info.timing_source)
+ || mt->mode_info.timing_source ==
+ TIMING_SOURCE_USER_FORCED ||
+ mt->mode_info.timing_source ==
+ TIMING_SOURCE_OS_FORCED ||
+ mt->mode_info.timing_source ==
+ TIMING_SOURCE_DALINTERFACE_EXPLICIT ||
+ mt->mode_info.timing_source ==
+ TIMING_SOURCE_DALINTERFACE_IMPLICIT)
+ /* Add timing for forced or customized mode*/
+ add_timing_to_candidate_list_with_priority(
+ bv,
+ &bv->identity_candidates,
+ mt);
+ else if (largest_mode != NULL && preferred_mode == NULL
+ && largest_native_mode == NULL
+ && largest_mode->pixel_width
+ == mt->mode_info.pixel_width
+ && largest_mode->pixel_height
+ == mt->mode_info.pixel_height) {
+ /* Add the largest timing as a candidate
+ * if no preferred or native timing found*/
+ add_timing_to_candidate_list_with_priority(
+ bv,
+ &bv->identity_candidates,
+ mt);
+ add_timing_to_candidate_list_with_priority(
+ bv,
+ &bv->scaled_candidates,
+ mt);
+ if (is_candidate_multiple_refresh_rate(mt))
+ add_timing_to_candidate_list_with_priority(
+ bv,
+ &bv->preferred_candidates,
+ mt);
+ }
+
+ /* we do not currently populate bv->preferred_candidates here
+ * since the GPU scaling bestview logic does not have a problem
+ * with intermediate timings blocking native refresh rates
+ * since they are pruned out already.
+ * We could add this but it would unlikely affect
+ * the final view solution.*/
+ }
+
+ print_bw_to_log(bv, "GpuScaling");
+ return true;
+}
+
+static bool best_view_single_selected_timing_construct(
+ struct best_view *bv,
+ struct best_view_init_data *bv_init_data)
+{
+ const struct mode_timing *selected_mode_timing;
+
+ if (bv_init_data == NULL ||
+ bv_init_data->mode_timing_list == NULL ||
+ !best_view_construct(bv, bv_init_data))
+ return false;
+
+ selected_mode_timing =
+ dal_mode_timing_list_get_single_selected_mode_timing(
+ bv_init_data->mode_timing_list);
+ if (selected_mode_timing == NULL) {
+ dal_logger_write(bv->ctx->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_MODE_ENUM_BEST_VIEW_CANDIDATES,
+ "%s: No timing to implement modes\n", __func__);
+ return false;
+ }
+ add_timing_to_candidate_list_with_priority(
+ bv,
+ &bv->identity_candidates,
+ selected_mode_timing);
+
+ add_timing_to_candidate_list_with_priority(
+ bv,
+ &bv->scaled_candidates,
+ selected_mode_timing);
+
+ print_bw_to_log(bv, "SingleSelected");
+ return true;
+}
+
+struct best_view *dal_best_view_create(
+ struct dal_context *ctx,
+ struct best_view_init_data *bv_init_data)
+{
+ struct best_view *bv;
+
+ if (bv_init_data == NULL)
+ return NULL;
+
+ bv = dal_alloc(sizeof(struct best_view));
+ if (bv == NULL)
+ return NULL;
+ bv->ctx = ctx;
+ /* We overriding timing selection from BestView option
+ * when this display requires special BestView */
+ if (dal_set_mode_params_report_single_selected_timing(
+ bv_init_data->set_mode_params,
+ bv_init_data->display_index)) {
+ if (!best_view_single_selected_timing_construct(
+ bv,
+ bv_init_data))
+ goto out_free_bv;
+
+ } else if (dal_set_mode_params_report_ce_mode_only(
+ bv_init_data->set_mode_params,
+ bv_init_data->display_index)) {
+ if (!best_view_ce_mode_only_construct(bv, bv_init_data))
+ goto out_free_bv;
+
+ } else
+ switch (bv_init_data->bv_option.base_timing_select) {
+ case TIMING_SELECT_NATIVE_ONLY:
+ if (!best_view_gpu_scaling_construct(bv, bv_init_data))
+ goto out_free_bv;
+ break;
+ case TIMING_SELECT_PRESERVE_ASPECT:
+ case TIMING_SELECT_DEFAULT:
+ default:
+ if (!best_view_default_construct(bv, bv_init_data))
+ goto out_free_bv;
+ }
+
+ return bv;
+out_free_bv:
+ dal_free(bv);
+ return NULL;
+}
+
+static void print_bw_to_log(const struct best_view *bv, const char *bv_type)
+{
+ dal_logger_write(bv->ctx->logger,
+ LOG_MAJOR_MODE_ENUM,
+ LOG_MINOR_MODE_ENUM_BEST_VIEW_CANDIDATES,
+ "Identity Candidates: %d entries\n",
+ dal_candidate_list_get_count(&bv->identity_candidates));
+ dal_candidate_list_print_to_log(&bv->identity_candidates);
+
+ dal_logger_write(bv->ctx->logger,
+ LOG_MAJOR_MODE_ENUM,
+ LOG_MINOR_MODE_ENUM_BEST_VIEW_CANDIDATES,
+ "Scaled Candidates: %d entries\n",
+ dal_candidate_list_get_count(&bv->scaled_candidates));
+ dal_candidate_list_print_to_log(&bv->scaled_candidates);
+
+ dal_logger_write(bv->ctx->logger,
+ LOG_MAJOR_MODE_ENUM,
+ LOG_MINOR_MODE_ENUM_BEST_VIEW_CANDIDATES,
+ "Preferred Candidates: %d entries\n",
+ dal_candidate_list_get_count(&bv->preferred_candidates));
+ dal_candidate_list_print_to_log(&bv->preferred_candidates);
+}
+
+static bool match_view_with_identity_timing(
+ struct best_view *bv,
+ const struct view *vw,
+ struct solution_set *target_list)
+{
+ bool found = false;
+ uint32_t index;
+ uint32_t i;
+ uint32_t identity_candidates_count;
+ struct mtp mtp;
+ struct scaling_support scaling_support;
+ const struct crtc_timing *crtc_timing;
+
+ if (dal_candidate_list_find_matching_view(
+ &bv->identity_candidates,
+ vw,
+ &index)) {
+ /* match all refresh rate of the same view in case
+ * there are multiple refresh rate supported on the view*/
+ identity_candidates_count =
+ dal_candidate_list_get_count(&bv->identity_candidates);
+ for (i = index; i < identity_candidates_count; i++) {
+ mtp = dal_candidate_list_at_index(
+ &bv->identity_candidates,
+ i);
+
+ if (mtp.value->mode_info.pixel_width == vw->width &&
+ mtp.value->mode_info.pixel_height ==
+ vw->height) {
+ dal_memset(
+ &scaling_support,
+ 0,
+ sizeof(struct scaling_support));
+
+ scaling_support.IDENTITY = true;
+ crtc_timing = &mtp.value->crtc_timing;
+ if (crtc_timing->h_addressable != vw->width ||
+ crtc_timing->v_addressable !=
+ vw->height) {
+ scaling_support.CENTER_TIMING = true;
+ scaling_support.
+ PRESERVE_ASPECT_RATIO_SCALE =
+ true;
+ scaling_support.FULL_SCREEN_SCALE =
+ true;
+ scaling_support.IDENTITY = false;
+ }
+ if (add_output_mode(
+ bv,
+ vw,
+ mtp,
+ scaling_support,
+ SOLUTION_IMPORTANCE_DEFAULT,
+ target_list))
+ found = true;
+
+ } else
+ break;
+ }
+ }
+ return found;
+}
+
+static bool match_view_with_next_higher_timing(
+ struct best_view *bv,
+ const struct view *vw,
+ struct solution_set *target_list,
+ const uint32_t start_index,
+ const bool allow_interlaced)
+{
+ uint32_t i, scaled_candidates_count;
+ struct scaling_support scaling_support;
+ const struct mode_info *candidate_mode_info = NULL;
+ /* candidate_mode_info points to the mode_info
+ * of the validated solution added to targetList*/
+ struct mtp mtp;
+
+ scaled_candidates_count = dal_candidate_list_get_count(
+ &bv->scaled_candidates);
+ for (i = start_index; i < scaled_candidates_count; i++) {
+ mtp = dal_candidate_list_at_index(&bv->scaled_candidates, i);
+
+ /* don't allow interlaced mode for matching*/
+ if (!allow_interlaced && mtp.value->mode_info.flags.INTERLACE)
+ continue;
+
+ /* we already matched a solution,
+ * so check if there are multiple timing
+ * of same resolution that we can use */
+ if (candidate_mode_info != NULL &&
+ (candidate_mode_info->pixel_height !=
+ mtp.value->mode_info.pixel_height ||
+ candidate_mode_info->pixel_width !=
+ mtp.value->mode_info.pixel_width))
+ /* the current timing is different in resolution
+ * compare to the timing we have used before,
+ * since scaled_candidate is sorted
+ * in ascending order, there aren't any more
+ * next higher resolution timing
+ * of different refresh rate,
+ * break and finish adding here*/
+ break;
+
+ /* the current timing passes above checks,
+ * it should be considered as solution */
+ dal_memset(&scaling_support, 0, sizeof(struct scaling_support));
+ scaling_support.CENTER_TIMING = true;
+ scaling_support.FULL_SCREEN_SCALE = true;
+ scaling_support.PRESERVE_ASPECT_RATIO_SCALE = true;
+
+ if (add_output_mode(
+ bv,
+ vw,
+ mtp,
+ scaling_support,
+ SOLUTION_IMPORTANCE_DEFAULT,
+ target_list))
+ candidate_mode_info = &(mtp.value->mode_info);
+ /* a solution was added successfully, remember the mode_info*/
+
+ }
+
+ return candidate_mode_info != NULL;
+}
+
+static bool match_view_with_next_lower_timing(
+ struct best_view *bv,
+ const struct view *vw,
+ struct solution_set *target_list,
+ const uint32_t start_index,
+ const bool allow_interlaced)
+{
+ int32_t i;
+ struct scaling_support scaling_support;
+ struct mtp mtp;
+
+ for (i = start_index; i >= 0; i--) {
+ mtp = dal_candidate_list_at_index(&bv->scaled_candidates, i);
+
+ if (allow_interlaced || !mtp.value->mode_info.flags.INTERLACE) {
+ dal_memset(
+ &scaling_support,
+ 0,
+ sizeof(struct scaling_support));
+
+ scaling_support.FULL_SCREEN_SCALE = true;
+ scaling_support.PRESERVE_ASPECT_RATIO_SCALE = true;
+
+ if (add_output_mode(
+ bv,
+ vw,
+ mtp,
+ scaling_support,
+ SOLUTION_IMPORTANCE_DEFAULT,
+ target_list))
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool match_view_with_preferred_higher_timing(
+ struct best_view *bv,
+ const struct view *vw,
+ struct solution_set *target_list)
+{
+ uint32_t i, j;
+ uint32_t preferred_list_size;
+ uint32_t target_list_size;
+
+ bool target_added = false;
+ bool found_target = false;
+ bool found_progressive = false;
+ bool found_custom = false;
+ bool found_non_custom = false;
+ struct scaling_support scaling_support;
+ struct solution *solution;
+ struct mtp mtp;
+ struct mtp target_mtp;
+
+ /* check that each of the supported preferred refresh rates
+ * have a solution*/
+ preferred_list_size = dal_candidate_list_get_count(
+ &bv->preferred_candidates);
+
+ for (i = 0; i < preferred_list_size; ++i) {
+ mtp = dal_candidate_list_at_index(&bv->preferred_candidates, i);
+
+ /* check that this view can fit within the timing */
+ if (vw->height > mtp.value->mode_info.pixel_height ||
+ vw->width > mtp.value->mode_info.pixel_width)
+ /* do not down scale, skip this timing for this view*/
+ continue;
+
+ /* check if any current target timing is already found
+ * for the refresh rate, if found preferred timing -
+ * raise solution level to preferred*/
+ target_list_size = solution_set_get_count(target_list);
+ for (j = 0; j < target_list_size; ++j) {
+ solution = solution_set_at_index(target_list, j);
+ target_mtp.value = solution->mode_timing;
+
+ /* If timing in this solution matches one
+ * from preferred list, raise solution level */
+ if (dal_mode_info_is_equal(
+ &mtp.value->mode_info,
+ &target_mtp.value->mode_info))
+ solution_update_importance(
+ solution,
+ SOLUTION_IMPORTANCE_PREFERRED);
+ if (found_target)
+ continue;
+
+ /* don't check video optimized flag
+ * since we don't want a non-video optimized
+ * preferred timing overriding a video-optimized one
+ * add different 3D formats as long
+ * as mode_info is the same
+ * to be able to enable 3D smoothly*/
+ if (mtp.value->mode_info.field_rate ==
+ target_mtp.value->mode_info.field_rate
+ &&
+ mtp.value->mode_info.flags.INTERLACE ==
+ target_mtp.value->mode_info.flags.
+ INTERLACE &&
+ (mtp.value->crtc_timing.timing_3d_format ==
+ target_mtp.value->crtc_timing.
+ timing_3d_format
+ || !dal_mode_info_is_equal(
+ &mtp.value->mode_info,
+ &target_mtp.value->mode_info)))
+ found_target = true;
+
+ if (!target_mtp.value->mode_info.flags.INTERLACE)
+ found_progressive = true;
+
+ /* do not use this timing as a target
+ * if there are existing custom timings already
+ * however need to take care
+ * where a custom mode has same view as an EDID mode */
+ if (is_custom_timing_source(target_mtp.value->mode_info.
+ timing_source))
+ found_custom = true;
+ else
+ found_non_custom = true;
+ }
+
+ /* if there is no timing for this refresh rate,
+ * add this timing as a solution, allow preferred refresh rates
+ * to be exposed on lower resolution modes
+ * mainly this will affect 120Hz monitors which have
+ * standard/established modes below native
+ * also check if progressive timings already exist
+ * in the target list if no progressive timings are found
+ * (only interlace timings), do not add this timing
+ * also if the target timing list contains
+ * only custom timings then don't add this timing*/
+ if (!found_target && found_progressive &&
+ (!found_custom || found_non_custom) &&
+ mtp.value->mode_info.field_rate >= 60) {
+ dal_memset(&scaling_support, 0,
+ sizeof(struct scaling_support));
+
+ scaling_support.CENTER_TIMING = true;
+ scaling_support.FULL_SCREEN_SCALE = true;
+ scaling_support.PRESERVE_ASPECT_RATIO_SCALE = true;
+
+ target_added = add_output_mode(
+ bv,
+ vw,
+ mtp,
+ scaling_support,
+ SOLUTION_IMPORTANCE_PREFERRED,
+ target_list);
+ }
+ }
+
+ return target_added;
+}
+
+bool dal_best_view_match_view_to_timing(
+ struct best_view *bv,
+ const struct view *vw,
+ struct solution_set *target_list)
+{
+ uint32_t index;
+ bool found = match_view_with_identity_timing(bv, vw, target_list);
+
+ if (!found) {
+ /* Either no timing found, or the timing is OS forced
+ * may not be able to use,
+ * in this case we need to look further*/
+ dal_candidate_list_find_matching_view(
+ &bv->scaled_candidates,
+ vw,
+ &index);
+ if (match_view_with_next_higher_timing(
+ bv,
+ vw,
+ target_list,
+ index,
+ false))
+ /* Next higher progress timing from base mode candidates
+ * is used as base mode*/
+ found = true;
+ else if (match_view_with_next_higher_timing(
+ bv,
+ vw,
+ target_list,
+ index,
+ true))
+ /* next higher interlaced timing
+ * from base mode candidates is used as base mode*/
+ found = true;
+ else if (index > 0) {
+ if (match_view_with_next_lower_timing(
+ bv,
+ vw,
+ target_list,
+ index - 1,
+ false))
+ /* next lower progressive timing from base mode
+ * candidates is used as base mode*/
+ found = true;
+ else if (match_view_with_next_lower_timing(
+ bv,
+ vw,
+ target_list,
+ index - 1,
+ true))
+ /* next lower interlaced timing from base mode
+ * candidates is used as base mode*/
+ found = true;
+ }
+
+ }
+
+ /* add additional refresh rates based on preferred resolution*/
+ match_view_with_preferred_higher_timing(bv, vw, target_list);
+
+ if (solution_set_get_count(target_list) > 0)
+ found = true;
+ else if (found)
+ BREAK_TO_DEBUGGER();
+
+ return found;
+}
+
+void dal_best_view_destroy(struct best_view **bv)
+{
+ if (bv == NULL || *bv == NULL)
+ return;
+ best_view_destruct(*bv);
+ dal_free(*bv);
+ *bv = NULL;
+}
+
+void dal_best_view_dump_statistics(struct best_view *bv)
+{
+ dal_logger_write(bv->ctx->logger,
+ LOG_MAJOR_MODE_ENUM,
+ LOG_MINOR_MODE_ENUM_BEST_VIEW_CANDIDATES,
+ "Path #%d contains %d supported PathMode combinations. %d PathModes are supported but not guaranteed\n",
+ bv->display_index,
+ bv->supported_path_mode_cnt,
+ bv->non_guaranteed_path_mode_cnt);
+}
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/best_view.h b/drivers/gpu/drm/amd/dal/mode_manager/best_view.h
new file mode 100644
index 000000000000..ac4e185e0846
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/best_view.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DAL_BEST_VIEW_H__
+#define __DAL_BEST_VIEW_H__
+
+#include "include/flat_set.h"
+#include "include/timing_service_types.h"
+#include "include/mode_manager_types.h"
+#include "candidate_list.h"
+#include "solution.h"
+
+union best_view_flags {
+ uint32_t value;
+ struct {
+ bool PREFER_3D_TIMING:1;
+ } bits;
+};
+
+struct mode_enum_override {
+ bool RESTRICT_ADAPTER_VIEW:1;
+ bool ALLOW_ONLY_BEST_VIEW_OVERRIDE_DISPLAY_VIEW:1;
+};
+
+struct scaling_support {
+ bool IDENTITY:1;
+ bool FULL_SCREEN_SCALE:1;
+ bool PRESERVE_ASPECT_RATIO_SCALE:1;
+ bool CENTER_TIMING:1;
+};
+
+struct best_view;
+
+struct best_biew_funcs {
+ enum display_view_importance (*get_view_importance_override)
+ (const struct best_view *bv, const struct view *view);
+};
+
+struct best_view {
+ const struct best_biew_funcs *funcs;
+ struct mode_enum_override mode_enum_override;
+ struct set_mode_params *set_mode_params;
+ uint32_t display_index; /* required for resource validation */
+ struct bestview_options options;
+ union best_view_flags flags;
+
+ struct candidate_list identity_candidates;
+ /*list of exact match candidate timings*/
+ struct candidate_list scaled_candidates;
+ /*list of base mode candidates*/
+ struct candidate_list preferred_candidates;
+ /*list of timings with a preferred refresh rates*/
+
+ uint32_t supported_path_mode_cnt;
+ uint32_t non_guaranteed_path_mode_cnt;
+ struct dal_context *ctx;
+};
+
+struct best_view_init_data {
+ struct set_mode_params *set_mode_params;
+ uint32_t display_index;
+ const struct bestview_options bv_option;
+ const union best_view_flags flags;
+ const struct mode_timing_list *mode_timing_list;
+};
+
+struct best_view *dal_best_view_create(
+ struct dal_context *ctx,
+ struct best_view_init_data *bv_init_data);
+void dal_best_view_destroy(struct best_view **bv);
+
+bool dal_best_view_match_view_to_timing(
+ struct best_view *bv,
+ const struct view *vw,
+ struct solution_set *target_list);
+
+void dal_best_view_dump_statistics(struct best_view *bv);
+
+#endif /*__DAL_BEST_VIEW_H__*/
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/candidate_list.c b/drivers/gpu/drm/amd/dal/mode_manager/candidate_list.c
new file mode 100644
index 000000000000..42e7b04b1c98
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/candidate_list.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dal_services.h"
+#include "include/timing_service_types.h"
+#include "include/set_mode_interface.h"
+#include "candidate_list.h"
+
+/* TODO appropriate value is to be defined */
+#define CANDIDATE_LIST_INITIAL_SIZE 100
+
+static bool mtp_less_than(
+ const void *lhs_address,
+ const void *rhs_address)
+{
+ const struct mtp *lhs = lhs_address;
+ const struct mtp *rhs = rhs_address;
+
+ return dal_mode_timing_less_than(lhs->value, rhs->value);
+}
+
+void dal_candidate_list_destruct(struct candidate_list *cl)
+{
+ dal_flat_set_destruct(&cl->mode_timing_set);
+}
+
+bool dal_candidate_list_construct(struct candidate_list *cl)
+{
+ struct flat_set_init_data fs_init_data = {
+ CANDIDATE_LIST_INITIAL_SIZE,
+ sizeof(struct mtp),
+ { mtp_less_than } };
+ return dal_flat_set_construct(&cl->mode_timing_set, &fs_init_data);
+}
+
+uint32_t dal_candidate_list_get_count(const struct candidate_list *cl)
+{
+ return dal_flat_set_get_count(&cl->mode_timing_set);
+}
+
+const struct mtp dal_candidate_list_at_index(
+ const struct candidate_list *cl,
+ uint32_t index)
+{
+ const struct mtp *mtp = dal_flat_set_at_index(
+ &cl->mode_timing_set,
+ index);
+ return *mtp;
+}
+
+bool dal_candidate_list_insert(
+ struct candidate_list *cl,
+ const struct mode_timing *mode_timing)
+{
+ struct mtp mtp = { mode_timing };
+
+ return dal_flat_set_insert(&cl->mode_timing_set, &mtp);
+}
+
+bool dal_candidate_list_remove_at_index(
+ struct candidate_list *cl,
+ uint32_t index)
+{
+ return dal_flat_set_remove_at_index(&cl->mode_timing_set, index);
+}
+
+bool dal_candidate_list_find_matching_view(
+ struct candidate_list *cl,
+ const struct view *vw,
+ uint32_t *index)
+{
+ /*
+ * The list contains pointer to mode timing, therefore create
+ * ModeTiming using the View to use native search that list
+ * provides
+ */
+ const struct mode_info *mode_info;
+ struct mode_timing mt = { { 0 } };
+ struct mtp mtp = { &mt };
+
+ mt.mode_info.pixel_width = vw->width;
+ mt.mode_info.pixel_height = vw->height;
+
+ dal_flat_set_search(&cl->mode_timing_set, &mtp, index);
+
+ /*
+ * Find will return false because mtp does not have full
+ * timing information. however, index will point to the closest
+ * ModeTiming with same x and y.
+ *
+ * if found, index will point to the ModeTiming of smallest refresh
+ * rate because *mtp's refresh rate is 0.
+ *
+ * return true if index returned is within bound and x,y matches
+ */
+
+ /* Index contains position after the last element */
+ if (*index == dal_candidate_list_get_count(cl))
+ return false;
+
+ mtp = dal_candidate_list_at_index(cl, *index);
+ mode_info = &(mtp.value->mode_info);
+
+ return mode_info->pixel_width == vw->width &&
+ mode_info->pixel_height == vw->height;
+}
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/candidate_list.h b/drivers/gpu/drm/amd/dal/mode_manager/candidate_list.h
new file mode 100644
index 000000000000..6228759f83db
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/candidate_list.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DAL_CANDIDATE_LIST_H__
+#define __DAL_CANDIDATE_LIST_H__
+
+#include "include/flat_set.h"
+
+struct mtp {
+ const struct mode_timing *value;
+};
+
+struct candidate_list {
+ struct flat_set mode_timing_set;
+};
+
+struct view;
+
+bool dal_candidate_list_construct(struct candidate_list *cl);
+
+void dal_candidate_list_destruct(struct candidate_list *cl);
+
+uint32_t dal_candidate_list_get_count(const struct candidate_list *cl);
+
+bool dal_candidate_list_insert(
+ struct candidate_list *cl,
+ const struct mode_timing *mode_timing);
+
+bool dal_candidate_list_remove_at_index(
+ struct candidate_list *cl,
+ uint32_t index);
+
+const struct mtp dal_candidate_list_at_index(
+ const struct candidate_list *cl,
+ uint32_t index);
+
+bool dal_candidate_list_find_matching_view(
+ struct candidate_list *cl,
+ const struct view *vw,
+ uint32_t *index);
+
+
+/* TODO to be implemented */
+static inline void dal_candidate_list_print_to_log(
+ const struct candidate_list *cl)
+{
+}
+
+#endif /*__DAL_CANDIDATE_LIST_H__*/
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/cofunctional_mode_query_validator.c b/drivers/gpu/drm/amd/dal/mode_manager/cofunctional_mode_query_validator.c
new file mode 100644
index 000000000000..a54b84424830
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/cofunctional_mode_query_validator.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dal_services.h"
+
+#include "include/topology_mgr_interface.h"
+
+#include "cofunctional_mode_validator.h"
+#include "cofunctional_mode_query_validator.h"
+#include "mode_query.h"
+
+
+struct cofunctional_mode_query_validator {
+ struct cofunctional_mode_validator cmv;
+
+ struct mode_query *mode_query[MAX_COFUNC_PATH];
+ uint32_t query_index[MAX_COFUNC_PATH];
+};
+
+static bool construct(
+ struct cofunctional_mode_query_validator *validator,
+ struct ds_dispatch *ds_dispatch)
+{
+ if (ds_dispatch)
+ return false;
+
+ if (!dal_cofunctional_mode_validator_construct(
+ &validator->cmv, ds_dispatch))
+ return false;
+
+ return true;
+}
+
+struct cofunctional_mode_query_validator *dal_cmqv_create(
+ struct ds_dispatch *ds_dispatch)
+{
+ struct cofunctional_mode_query_validator *validator =
+ dal_alloc(sizeof(struct cofunctional_mode_query_validator));
+
+ if (construct(validator, ds_dispatch))
+ return validator;
+
+ dal_free(validator);
+ return NULL;
+}
+
+static void destruct(struct cofunctional_mode_query_validator *cmqv)
+{
+ dal_cofunctional_mode_validator_destruct(&cmqv->cmv);
+}
+
+void dal_cmqv_destroy(struct cofunctional_mode_query_validator **cmqv)
+{
+ if (!cmqv || !*cmqv) {
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+
+ destruct(*cmqv);
+ dal_free(*cmqv);
+ *cmqv = NULL;
+}
+
+bool dal_cmqv_add_mode_query(
+ struct cofunctional_mode_query_validator *validator,
+ struct mode_query *mq)
+{
+ const struct topology *topology = &mq->topology;
+ uint32_t i;
+ uint32_t count =
+ dal_pms_get_path_mode_num(validator->cmv.pms);
+ struct path_mode pm = {};
+
+ for (i = 0; i < topology->disp_path_num; i++) {
+ if (count >= MAX_COFUNC_PATH)
+ return false; /* too many displays */
+
+ if (dal_pms_get_path_mode_at_index(
+ validator->cmv.pms,
+ topology->display_index[i]))
+ return false; /* duplicate display index */
+
+ /* set up index for future access */
+ validator->mode_query[count] = mq;
+ validator->query_index[count] = i;
+
+ pm.display_path_index = topology->display_index[i];
+
+ dal_pms_add_path_mode(validator->cmv.pms, &pm);
+ }
+
+ return true;
+}
+
+void dal_cmqv_update_mode_query(
+ struct cofunctional_mode_query_validator *validator,
+ struct mode_query *mq)
+{
+ uint32_t i;
+ uint32_t count = dal_pms_get_path_mode_num(validator->cmv.pms);
+
+ for (i = 0; i < count; ++i) {
+ struct mode_query *mq = validator->mode_query[i];
+
+ dal_mode_query_update_validator_entry(
+ mq, &validator->cmv, i, validator->query_index[i]);
+ }
+}
+
+bool dal_cmqv_is_cofunctional(
+ struct cofunctional_mode_query_validator *validator)
+{
+ return dal_cofunctional_mode_validator_is_cofunctional(&validator->cmv);
+}
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/cofunctional_mode_query_validator.h b/drivers/gpu/drm/amd/dal/mode_manager/cofunctional_mode_query_validator.h
new file mode 100644
index 000000000000..44d6c151b4fd
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/cofunctional_mode_query_validator.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "cofunctional_mode_validator.h"
+
+struct cofunctional_mode_query_validator;
+
+struct ds_dispatch;
+struct mode_query;
+
+struct cofunctional_mode_query_validator *dal_cmqv_create(
+ struct ds_dispatch *ds_dispatch);
+
+void dal_cmqv_destroy(struct cofunctional_mode_query_validator **cmqv);
+
+bool dal_cmqv_add_mode_query(
+ struct cofunctional_mode_query_validator *validator,
+ struct mode_query *mq);
+
+void dal_cmqv_update_mode_query(
+ struct cofunctional_mode_query_validator *validator,
+ struct mode_query *mq);
+
+bool dal_cmqv_is_cofunctional(
+ struct cofunctional_mode_query_validator *validator);
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/cofunctional_mode_validator.c b/drivers/gpu/drm/amd/dal/mode_manager/cofunctional_mode_validator.c
new file mode 100644
index 000000000000..1072a3a13373
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/cofunctional_mode_validator.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dal_services.h"
+#include "cofunctional_mode_validator.h"
+
+struct ds_dispatch;
+
+bool dal_cofunctional_mode_validator_construct(
+ struct cofunctional_mode_validator *cofunctional_mode_validator,
+ const struct ds_dispatch *ds_dispatch)
+{
+ cofunctional_mode_validator->ds_dispatch = ds_dispatch;
+ cofunctional_mode_validator->pinned_path_mode_count = 0;
+ cofunctional_mode_validator->validate_req_vector = 0;
+ cofunctional_mode_validator->set_mode_params = NULL;
+ cofunctional_mode_validator->sync_capability = SYNC_CAP_STATE_UNKNOWN;
+ cofunctional_mode_validator->pms = dal_pms_create();
+ if (cofunctional_mode_validator->pms == NULL)
+ return false;
+ return true;
+}
+
+void dal_cofunctional_mode_validator_destruct(
+ struct cofunctional_mode_validator *cofunctional_mode_validator)
+{
+ dal_pms_destroy(&cofunctional_mode_validator->pms);
+}
+
+static bool validate(struct cofunctional_mode_validator *cmv)
+{
+ uint32_t i;
+ uint32_t mode_count = get_total_mode_count(cmv);
+
+ if (cmv->set_mode_params == NULL) {
+ uint32_t disp_idx[MAX_COFUNC_PATH];
+
+ for (i = 0; i < mode_count; i++)
+ disp_idx[i] = cofunctional_mode_validator_get_at(
+ cmv, i)->display_path_index;
+
+ cmv->set_mode_params =
+ dal_ds_dispatch_create_resource_context(
+ cmv->ds_dispatch,
+ disp_idx,
+ get_total_mode_count(cmv));
+ }
+
+ if (cmv->set_mode_params == NULL)
+ return false;
+
+
+ for (i = 0; i < mode_count; i++) {
+ const struct path_mode *path_mode =
+ cofunctional_mode_validator_get_at(cmv, i);
+
+ if (!dal_set_mode_params_update_view_on_path(
+ cmv->set_mode_params,
+ path_mode->display_path_index,
+ &path_mode->view))
+ return false;
+
+ if (!dal_set_mode_params_update_pixel_format_on_path(
+ cmv->set_mode_params,
+ path_mode->display_path_index,
+ path_mode->pixel_format))
+ return false;
+
+ if (!dal_set_mode_params_update_mode_timing_on_path(
+ cmv->set_mode_params,
+ path_mode->display_path_index,
+ path_mode->mode_timing,
+ path_mode->view_3d_format))
+ return false;
+
+ if (!dal_set_mode_params_update_scaling_on_path(
+ cmv->set_mode_params,
+ path_mode->display_path_index,
+ path_mode->scaling))
+ return false;
+
+ if (!dal_set_mode_params_update_tiling_mode_on_path(
+ cmv->set_mode_params,
+ path_mode->display_path_index,
+ path_mode->tiling_mode))
+ return false;
+ }
+
+ return dal_set_mode_params_is_path_mode_set_supported(
+ cmv->set_mode_params);
+}
+
+bool dal_cofunctional_mode_validator_is_cofunctional(
+ struct cofunctional_mode_validator *cmv)
+{
+ if (get_total_mode_count(cmv) > 1)
+ if (cmv->validate_req_vector != 0)
+ return validate(cmv);
+
+ return true;
+}
+
+void dal_cofunctional_mode_validator_flag_guaranteed_at(
+ struct cofunctional_mode_validator *validator,
+ uint32_t index,
+ bool guaranteed)
+{
+ ASSERT(index < validator->pms->count);
+
+ if (guaranteed)
+ validator->validate_req_vector &= ~(1 << index);
+ else
+ validator->validate_req_vector |= (1 << index);
+}
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/cofunctional_mode_validator.h b/drivers/gpu/drm/amd/dal/mode_manager/cofunctional_mode_validator.h
new file mode 100644
index 000000000000..5f18492a1a4f
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/cofunctional_mode_validator.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DAL_COFUNCTIONAL_MODE_VALIDATOR_H__
+#define __DAL_COFUNCTIONAL_MODE_VALIDATOR_H__
+
+#include "include/set_mode_interface.h"
+
+enum sync_cap_state {
+ SYNC_CAP_STATE_UNKNOWN,
+ SYNC_CAP_STATE_CAPABLE,
+ SYNC_CAP_STATE_INCAPABLE
+};
+
+struct path_mode_set;
+
+struct cofunctional_mode_validator {
+ struct path_mode_set *pms;
+ const struct ds_dispatch *ds_dispatch;
+ uint32_t pinned_path_mode_count;
+ uint32_t validate_req_vector;
+ enum sync_cap_state sync_capability;
+ struct set_mode_params *set_mode_params;
+};
+bool dal_cofunctional_mode_validator_construct(
+ struct cofunctional_mode_validator *cofunctional_mode_validator,
+ const struct ds_dispatch *ds_dispatch);
+
+void dal_cofunctional_mode_validator_destruct(
+ struct cofunctional_mode_validator *cofunctional_mode_validator);
+
+bool dal_cofunctional_mode_validator_is_cofunctional(
+ struct cofunctional_mode_validator *cmv);
+
+static inline uint32_t get_total_mode_count(
+ const struct cofunctional_mode_validator *cmv)
+{
+ return cmv->pinned_path_mode_count + dal_pms_get_path_mode_num(
+ cmv->pms);
+}
+
+static inline struct path_mode *cofunctional_mode_validator_get_at(
+ struct cofunctional_mode_validator *cmv, uint32_t i)
+{
+ return &cmv->pms->path_mode_set[i];
+}
+
+static inline bool dal_cofunctional_mode_validator_add_path_mode(
+ struct cofunctional_mode_validator *cmv,
+ struct path_mode *path_mode)
+{
+ return dal_pms_add_path_mode(cmv->pms, path_mode);
+}
+
+void dal_cofunctional_mode_validator_flag_guaranteed_at(
+ struct cofunctional_mode_validator *validator,
+ uint32_t index,
+ bool guaranteed);
+
+#endif /* __DAL_COFUNCTIONAL_MODE_VALIDATOR_H__ */
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/display_view_solution_container.c b/drivers/gpu/drm/amd/dal/mode_manager/display_view_solution_container.c
new file mode 100644
index 000000000000..fbfca8d6ab49
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/display_view_solution_container.c
@@ -0,0 +1,502 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dal_services.h"
+
+#include "include/mode_timing_list_interface.h"
+#include "include/logger_interface.h"
+
+#include "display_view_solution_container.h"
+#include "solution.h"
+
+DAL_VECTOR_AT_INDEX(solution_key, struct solution_key *);
+DAL_VECTOR_INSERT_AT(solution_key, struct solution_key *);
+DAL_VECTOR_APPEND(solution_store, struct solution *);
+
+struct view_solution dal_dvsc_get_view_solution_at_index(
+ const struct display_view_solution_container *dvsc,
+ uint32_t index)
+{
+ struct view_solution vw_sol;
+
+ view_solution_construct(
+ &vw_sol,
+ &dal_view_info_list_at_index(
+ dvsc->master_view_list,
+ index)->view,
+ dvsc->store,
+ solution_key_vector_at_index(dvsc->keys, index));
+
+ dal_logger_write(
+ dvsc->ctx->logger,
+ LOG_MAJOR_MODE_ENUM,
+ LOG_MINOR_MODE_ENUM_VIEW_SOLUTION,
+ "%s: %i %ix%i start_index=%i count=%i importance=%i\n",
+ __func__,
+ index,
+ vw_sol.view->width,
+ vw_sol.view->height,
+ vw_sol.key->start_index,
+ vw_sol.key->count,
+ vw_sol.key->importance);
+
+ return vw_sol;
+}
+
+bool dal_dvsc_grow(
+ struct display_view_solution_container *dvsc,
+ uint32_t count)
+{
+ if (!dal_vector_reserve(dvsc->keys, count))
+ return false;
+ if (!dal_vector_reserve(dvsc->store, count))
+ return false;
+ return true;
+}
+
+static const struct bestview_options HDMI_BEST_VIEW_DEFAULT_OPTION = {
+ TIMING_SELECT_DEFAULT, /* base_timing_select */
+ DISPLAY_COLOR_DEPTH_101010, /* prefered_color_depth */
+ PIXEL_ENCODING_YCBCR444, /* prefered_pixel_encoding */
+ false, /* RESTRICT_HD_TIMING */
+ false, /* DISALLOW_CUSTOM_MODES_AS_BASE */
+ false, /* MAINTAIN_ASPECT_RATIO */
+ true /* ENABLE_SCALING */
+};
+
+static const struct bestview_options BEST_VIEW_DEFAULT_OPTION = {
+ TIMING_SELECT_DEFAULT, /* base_timing_select */
+ DISPLAY_COLOR_DEPTH_101010, /* prefered_color_depth */
+ PIXEL_ENCODING_RGB, /* prefered_pixel_encoding */
+ false, /* RESTRICT_HD_TIMING */
+ false, /* DISALLOW_CUSTOM_MODES_AS_BASE */
+ false, /* MAINTAIN_ASPECT_RATIO */
+ true /* ENABLE_SCALING */
+};
+
+static void restore_best_view_option(
+ struct display_view_solution_container *dvsc)
+{
+ /* TODO: temporary disable bestview restore until final logic
+ * identified */
+ return;
+ dvsc->best_view_options = BEST_VIEW_DEFAULT_OPTION;
+ dvsc->hdmi_default_options = HDMI_BEST_VIEW_DEFAULT_OPTION;
+ dvsc->hdmi_options = HDMI_BEST_VIEW_DEFAULT_OPTION;
+
+ if (dvsc->set_mode_params != NULL &&
+ dal_set_mode_params_is_multiple_pixel_encoding_supported(
+ dvsc->set_mode_params, dvsc->display_index)) {
+ /* default setting in not persistent data. */
+
+ if (dal_set_mode_params_get_default_pixel_format_preference(
+ dvsc->set_mode_params, dvsc->display_index))
+ /* if FID9204 is applicable then we do RGB */
+ dvsc->hdmi_default_options.prefered_pixel_encoding =
+ PIXEL_ENCODING_RGB;
+ }
+}
+
+static bool construct(
+ struct display_view_solution_container *dvsc,
+ const struct display_view_solution_container_init_data *dvsc_init_data)
+{
+ uint32_t display_index_array[] = { dvsc_init_data->display_index };
+
+ dvsc->display_index = dvsc_init_data->display_index;
+ dvsc->master_view_list = dvsc_init_data->master_view_list;
+ dvsc->bv_flags = dvsc_init_data->bv_flags;
+ if (dvsc_init_data->ds_dispatch == NULL)
+ return false;
+
+ dvsc->keys = dal_vector_create(
+ dvsc_init_data->capacity,
+ sizeof(struct solution_key));
+
+ if (dvsc->keys == NULL)
+ return false;
+
+ dvsc->ctx = dvsc_init_data->dal_context;
+ dvsc->ds_dispatch = dvsc_init_data->ds_dispatch;
+ dvsc->best_view = NULL;
+ dvsc->is_valid = false;
+ dvsc->store = dal_vector_create(
+ dvsc_init_data->capacity,
+ sizeof(struct solution));
+
+ if (dvsc->store == NULL)
+ goto out_destruct_key_list;
+
+ dvsc->set_mode_params = dal_ds_dispatch_create_resource_context(
+ dvsc_init_data->ds_dispatch,
+ display_index_array,
+ 1);
+
+ if (dvsc->set_mode_params == NULL)
+ goto out_destruct_solution_store;
+
+ if (!dal_solution_set_construct(&dvsc->output_mode_list))
+ goto out_destruct_set_mode_params;
+
+ restore_best_view_option(dvsc);
+ return true;
+out_destruct_set_mode_params:
+ dal_set_mode_params_destroy(&dvsc->set_mode_params);
+out_destruct_solution_store:
+ dal_vector_destroy(&dvsc->store);
+out_destruct_key_list:
+ dal_vector_destroy(&dvsc->keys);
+ return false;
+}
+
+struct display_view_solution_container *dal_dvsc_create(
+ const struct display_view_solution_container_init_data *dvsc_init_data)
+{
+ struct display_view_solution_container *dvsc = dal_alloc(
+ sizeof(struct display_view_solution_container));
+
+ if (dvsc == NULL)
+ return NULL;
+
+ if (construct(dvsc, dvsc_init_data))
+ return dvsc;
+
+ dal_free(dvsc);
+ return NULL;
+}
+
+static void destruct(struct display_view_solution_container *dvsc)
+{
+ dal_vector_destroy(&dvsc->keys);
+ dal_vector_destroy(&dvsc->store);
+ dal_best_view_destroy(&dvsc->best_view);
+ dal_set_mode_params_destroy(&dvsc->set_mode_params);
+ solution_set_destruct(&dvsc->output_mode_list);
+}
+
+void dal_dvsc_destroy(struct display_view_solution_container **dvsc)
+{
+ if (dvsc == NULL || *dvsc == NULL)
+ return;
+ destruct(*dvsc);
+ dal_free(*dvsc);
+ *dvsc = NULL;
+}
+
+void dal_dvsc_save_bestview_options(
+ struct display_view_solution_container *dvsc,
+ const struct bestview_options *opts)
+{
+ if (!opts)
+ return;
+
+ if (dvsc->set_mode_params &&
+ dal_set_mode_params_is_multiple_pixel_encoding_supported(
+ dvsc->set_mode_params,
+ dvsc->display_index))
+ dvsc->hdmi_options = *opts;
+ else
+ dvsc->best_view_options = *opts;
+}
+
+struct bestview_options dal_dvsc_get_default_bestview_options(
+ struct display_view_solution_container *dvsc)
+{
+ if (dvsc->set_mode_params &&
+ dal_set_mode_params_is_multiple_pixel_encoding_supported(
+ dvsc->set_mode_params,
+ dvsc->display_index))
+ return dvsc->hdmi_default_options;
+ else
+ return BEST_VIEW_DEFAULT_OPTION;
+}
+
+
+struct bestview_options dal_dvsc_get_bestview_options(
+ struct display_view_solution_container *dvsc)
+{
+ if (dvsc->set_mode_params &&
+ dal_set_mode_params_is_multiple_pixel_encoding_supported(
+ dvsc->set_mode_params,
+ dvsc->display_index))
+ return dvsc->hdmi_options;
+ return dvsc->best_view_options;
+}
+
+void dal_dvsc_update_view_importance(
+ struct display_view_solution_container *dvsc,
+ uint32_t index,
+ enum display_view_importance importance)
+{
+ struct solution_key *key = solution_key_vector_at_index(
+ dvsc->keys, index);
+
+ if (importance < key->importance)
+ key->importance = importance;
+}
+
+static const enum scaling_transformation SCALING_ENUM_ORDER_PAR[] = {
+ SCALING_TRANSFORMATION_IDENTITY,
+ SCALING_TRANSFORMATION_PRESERVE_ASPECT_RATIO_SCALE,
+ SCALING_TRANSFORMATION_FULL_SCREEN_SCALE,
+ SCALING_TRANSFORMATION_CENTER_TIMING,
+ SCALING_TRANSFORMATION_INVALID };
+
+static const enum scaling_transformation SCALING_ENUM_ORDER_FS[] = {
+ SCALING_TRANSFORMATION_IDENTITY,
+ SCALING_TRANSFORMATION_FULL_SCREEN_SCALE,
+ SCALING_TRANSFORMATION_PRESERVE_ASPECT_RATIO_SCALE,
+ SCALING_TRANSFORMATION_CENTER_TIMING,
+ SCALING_TRANSFORMATION_INVALID };
+
+static const enum scaling_transformation SCALING_ENUM_ORDER_CENTER[] = {
+ SCALING_TRANSFORMATION_IDENTITY,
+ SCALING_TRANSFORMATION_CENTER_TIMING,
+ SCALING_TRANSFORMATION_PRESERVE_ASPECT_RATIO_SCALE,
+ SCALING_TRANSFORMATION_FULL_SCREEN_SCALE,
+ SCALING_TRANSFORMATION_INVALID };
+
+enum scaling_transformation dal_dvsc_get_preferred_scaling(
+ struct display_view_solution_container *dvsc)
+{
+ /* The order is important. If aspect_ratio set, we assume that scaler
+ * enabled and report aspect_ratio
+ * If aspect_ratio not set, but scaler enabled - we scale to full screen
+ * If both unset - we report Centered Timing
+ * Generally we have one more state - aspect_ratio set, but scaler
+ * disabled. Currently we report aspect_ratio, but this state could be
+ * used for some special case
+ */
+ struct bestview_options opts = dal_dvsc_get_bestview_options(dvsc);
+
+ if (!opts.ENABLE_SCALING)
+ return SCALING_TRANSFORMATION_CENTER_TIMING;
+
+ if (opts.MAINTAIN_ASPECT_RATIO)
+ return SCALING_TRANSFORMATION_PRESERVE_ASPECT_RATIO_SCALE;
+ else
+ return SCALING_TRANSFORMATION_FULL_SCREEN_SCALE;
+}
+
+static enum mode_aspect_ratio get_aspect_ratio_for_mode(
+ const struct mode_info *mi)
+{
+ if (mi->pixel_width * 3 == mi->pixel_height * 4)
+ return MODE_ASPECT_RATIO_4X3;
+ else if (mi->pixel_width * 4 == mi->pixel_height * 5)
+ return MODE_ASPECT_RATIO_5X4;
+ else if (mi->pixel_width * 9 == mi->pixel_height * 16)
+ return MODE_ASPECT_RATIO_16X9;
+ else if (mi->pixel_width * 10 == mi->pixel_height * 16)
+ return MODE_ASPECT_RATIO_16X10;
+
+ return MODE_ASPECT_RATIO_UNKNOWN;
+}
+
+static void update_display_aspect_ratio(
+ struct display_view_solution_container *dvsc)
+{
+ enum mode_aspect_ratio aspect = MODE_ASPECT_RATIO_UNKNOWN;
+ uint32_t i;
+
+ for (i = dal_mode_timing_list_get_count(dvsc->mtl); i > 0; --i) {
+ const struct mode_info *mi =
+ &(dal_mode_timing_list_get_timing_at_index(
+ dvsc->mtl,
+ i - 1)->mode_info);
+
+ if (mi->flags.PREFERRED || mi->flags.NATIVE) {
+ aspect = get_aspect_ratio_for_mode(mi);
+
+ if (aspect != MODE_ASPECT_RATIO_UNKNOWN)
+ break;
+ }
+ }
+
+ dvsc->mode_aspect_ratio = aspect;
+
+}
+
+bool dal_dvsc_update(
+ struct display_view_solution_container *dvsc,
+ const struct mode_timing_list *mtl)
+{
+ uint32_t i;
+ uint32_t count;
+ struct bestview_options opts;
+ /* container is valid only if we update properly */
+ dvsc->is_valid = false;
+
+ /* process rebuild */
+ dvsc->mtl = mtl;
+ update_display_aspect_ratio(dvsc);
+
+ /* recreate resource validation context */
+ if (dvsc->set_mode_params != NULL)
+ dal_set_mode_params_destroy(&dvsc->set_mode_params);
+
+ dvsc->set_mode_params =
+ dal_ds_dispatch_create_resource_context(
+ dvsc->ds_dispatch,
+ &dvsc->display_index,
+ 1);
+
+ if (dvsc->set_mode_params == NULL) {
+ dal_logger_write(dvsc->ctx->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_MODE_ENUM_VIEW_SOLUTION,
+ "%s - Out of Memory\n", __func__);
+ return false;
+ }
+
+ /* add restore_best_view_option here to make a chance to update the hdmi
+ * best view option for the passive dongle case */
+ restore_best_view_option(dvsc);
+
+ opts = dal_dvsc_get_bestview_options(dvsc);
+
+ /* Update Scaling Enum Order according to input options */
+ switch (dal_dvsc_get_preferred_scaling(dvsc)) {
+ case SCALING_TRANSFORMATION_PRESERVE_ASPECT_RATIO_SCALE:
+ dvsc->scl_enum_order_list = SCALING_ENUM_ORDER_PAR;
+ break;
+ case SCALING_TRANSFORMATION_CENTER_TIMING:
+ dvsc->scl_enum_order_list = SCALING_ENUM_ORDER_CENTER;
+ break;
+ case SCALING_TRANSFORMATION_FULL_SCREEN_SCALE:
+ default:
+ dvsc->scl_enum_order_list = SCALING_ENUM_ORDER_FS;
+ break;
+ }
+
+ /* Update the best view object to be used to build view to timing
+ * association */
+ if (dvsc->best_view)
+ dal_best_view_destroy(&dvsc->best_view);
+
+ {
+ struct best_view_init_data data = {
+ dvsc->set_mode_params,
+ dvsc->display_index,
+ opts,
+ dvsc->bv_flags,
+ mtl
+ };
+ dvsc->best_view = dal_best_view_create(dvsc->ctx, &data);
+ }
+
+ if (dvsc->best_view == NULL) {
+ dal_logger_write(dvsc->ctx->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_MODE_ENUM_VIEW_SOLUTION,
+ "%s - Out of Memory\n", __func__);
+ return false;
+ }
+
+ /* clear current associations */
+ dal_vector_clear(dvsc->keys);
+ dal_vector_clear(dvsc->store);
+
+ /* build timing associations for all views currently in master view list
+ */
+ count = dal_view_info_list_get_count(dvsc->master_view_list);
+ for (i = 0; i < count; ++i)
+ dal_dvsc_notify_newly_inserted_view_at_index(dvsc, i);
+
+ dal_best_view_dump_statistics(dvsc->best_view);
+ dvsc->is_valid = true;
+
+ return true;
+}
+
+bool dal_dvsc_notify_newly_inserted_view_at_index(
+ struct display_view_solution_container *dvsc, uint32_t index)
+{
+ const struct view *view;
+ struct solution_key key = {0};
+ /* TODO this should never happen. Investigate why dvsc->best_view is
+ * ever NULL! */
+ if (dvsc->best_view == NULL) {
+ dal_logger_write(dvsc->ctx->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_MODE_ENUM_VIEW_SOLUTION,
+ " %s:%d: best_view is NULL\n", __func__, __LINE__);
+ return false;
+ }
+
+ view = &(dal_view_info_list_at_index(
+ dvsc->master_view_list, index)->view);
+
+ solution_set_clear(&dvsc->output_mode_list);
+
+ key.importance = dvsc->best_view->funcs->get_view_importance_override(
+ dvsc->best_view, view);
+
+ if (dal_best_view_match_view_to_timing(
+ dvsc->best_view, view, &dvsc->output_mode_list)) {
+ uint32_t i;
+ uint32_t count =
+ solution_set_get_count(&dvsc->output_mode_list);
+ key.start_index = dal_vector_get_count(dvsc->store);
+
+ for (i = 0; i < count; ++i) {
+ if (!solution_store_vector_append(
+ dvsc->store,
+ solution_set_at_index(
+ &dvsc->output_mode_list,
+ i)))
+ dal_logger_write(dvsc->ctx->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_MODE_ENUM_VIEW_SOLUTION,
+ "%s - Out of Memory\n", __func__);
+ }
+
+ key.count = dal_vector_get_count(dvsc->store) -
+ key.start_index;
+ } else
+ key.count = 0;
+
+ if (!solution_key_vector_insert_at(dvsc->keys, &key, index))
+ dal_logger_write(dvsc->ctx->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_MODE_ENUM_VIEW_SOLUTION,
+ "%s - Out of Memory\n", __func__);
+
+ dal_logger_write(
+ dvsc->ctx->logger,
+ LOG_MAJOR_MODE_ENUM,
+ LOG_MINOR_MODE_ENUM_VIEW_SOLUTION,
+ "%s: display_path=%i, view_index=%i %ix%i start_index=%i count=%i importance=%i\n",
+ __func__,
+ dvsc->display_index,
+ index,
+ view->width,
+ view->height,
+ key.start_index,
+ key.count,
+ key.importance);
+
+ return true;
+}
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/display_view_solution_container.h b/drivers/gpu/drm/amd/dal/mode_manager/display_view_solution_container.h
new file mode 100644
index 000000000000..10eeb3ba817d
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/display_view_solution_container.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DAL_DISPLAY_VIEW_SOLUTION_CONTAINER_H__
+#define __DAL_DISPLAY_VIEW_SOLUTION_CONTAINER_H__
+
+#include "include/mode_manager_types.h"
+#include "best_view.h"
+#include "view_solution.h"
+
+struct display_view_solution_container {
+ uint32_t display_index;
+ bool is_valid;
+ struct set_mode_params *set_mode_params;
+ const struct ds_dispatch *ds_dispatch;
+
+ const struct view_info_list *master_view_list;
+
+ const struct mode_timing_list *mtl;
+
+ struct vector *keys;
+ struct vector *store;
+
+ struct best_view *best_view;
+ struct bestview_options best_view_options;
+ struct bestview_options hdmi_options;
+ struct bestview_options hdmi_default_options;
+ union best_view_flags bv_flags;
+
+ const enum scaling_transformation *scl_enum_order_list;
+
+ enum mode_aspect_ratio mode_aspect_ratio;
+ struct dal_context *ctx;
+
+ struct solution_set output_mode_list;
+};
+
+static inline struct view_stereo_3d_support
+ dvsc_get_stereo_3d_support(
+ const struct display_view_solution_container *dvsc,
+ enum timing_3d_format timing_3d_format)
+{
+ if (dvsc->set_mode_params == NULL) {
+ struct view_stereo_3d_support view_stereo_3d_support = {
+ VIEW_3D_FORMAT_NONE, { 0, 0 } };
+ return view_stereo_3d_support;
+ }
+ return dal_set_mode_params_get_stereo_3d_support(
+ dvsc->set_mode_params,
+ dvsc->display_index,
+ timing_3d_format);
+}
+
+struct view_solution dal_dvsc_get_view_solution_at_index(
+ const struct display_view_solution_container *dvsc,
+ uint32_t index);
+
+bool dal_dvsc_grow(struct display_view_solution_container *dvsc,
+ uint32_t count);
+
+struct bestview_options dal_dvsc_get_bestview_options(
+ struct display_view_solution_container *dvsc);
+
+struct bestview_options dal_dvsc_get_default_bestview_options(
+ struct display_view_solution_container *dvsc);
+
+void dal_dvsc_save_bestview_options(
+ struct display_view_solution_container *dvsc,
+ const struct bestview_options *opts);
+
+void dal_dvsc_update_view_importance(
+ struct display_view_solution_container *dvsc,
+ uint32_t index,
+ enum display_view_importance importance);
+
+bool dal_dvsc_notify_newly_inserted_view_at_index(
+ struct display_view_solution_container *dvsc, uint32_t index);
+
+bool dal_dvsc_update(
+ struct display_view_solution_container *dvsc,
+ const struct mode_timing_list *mtl);
+
+struct display_view_solution_container_init_data {
+ const struct ds_dispatch *ds_dispatch;
+ uint32_t display_index;
+ const struct view_info_list *master_view_list;
+ union best_view_flags bv_flags;
+ uint32_t capacity;
+ struct dal_context *dal_context;
+};
+
+struct display_view_solution_container *dal_dvsc_create(
+ const struct display_view_solution_container_init_data
+ *dvsc_init_data);
+
+void dal_dvsc_destroy(struct display_view_solution_container **dvsc);
+
+#endif /* __DAL_DISPLAY_VIEW_SOLUTION_CONTAINER_H__ */
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/mode_manager.c b/drivers/gpu/drm/amd/dal/mode_manager/mode_manager.c
new file mode 100644
index 000000000000..1505dad7eec9
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/mode_manager.c
@@ -0,0 +1,812 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dal_services.h"
+
+#include "include/adapter_service_interface.h"
+#include "include/logger_interface.h"
+#include "include/timing_service_interface.h"
+#include "include/default_mode_list_interface.h"
+#include "include/mode_timing_list_interface.h"
+#include "include/mode_manager_interface.h"
+
+#include "mode_query.h"
+#include "mode_query_allow_pan.h"
+#include "mode_query_no_pan.h"
+#include "view_solution.h"
+#include "best_view.h"
+#include "mode_query.h"
+#include "cofunctional_mode_query_validator.h"
+
+static struct view_info guaranteed_view_info[] = {
+ { { 640, 480 }, { ADAPTER_VIEW_IMPORTANCE_GUARANTEED } },
+ { { 800, 600 }, { ADAPTER_VIEW_IMPORTANCE_GUARANTEED } },
+ { { 1024, 768 }, { ADAPTER_VIEW_IMPORTANCE_GUARANTEED } },
+ { { 1280, 720 }, { ADAPTER_VIEW_IMPORTANCE_GUARANTEED_16x9 } },
+ { { 1280, 800 }, { ADAPTER_VIEW_IMPORTANCE_GUARANTEED_16x10 } },
+ { { 1280, 1024 }, { ADAPTER_VIEW_IMPORTANCE_GUARANTEED } },
+ { { 1600, 900 }, { ADAPTER_VIEW_IMPORTANCE_GUARANTEED_16x9 } },
+ { { 1600, 1200 }, { ADAPTER_VIEW_IMPORTANCE_GUARANTEED } },
+ { { 1680, 1050 }, { ADAPTER_VIEW_IMPORTANCE_GUARANTEED_16x10 } }, };
+
+struct mode_manager {
+ struct ds_dispatch *ds_dispatch;
+ struct adapter_service *as;
+
+ struct view_info_list master_view_list;
+ struct vector solution_container_list;
+ uint32_t supported_pixel_format;
+ uint32_t pixel_granularity;
+ struct dal_context *ctx;
+};
+
+DAL_VECTOR_AT_INDEX(solution_container,
+ struct display_view_solution_container **);
+DAL_VECTOR_APPEND(solution_container,
+ struct display_view_solution_container **);
+
+static void destruct(struct mode_manager *mm)
+{
+ uint32_t i;
+
+ dal_view_info_list_destruct(&mm->master_view_list);
+
+ for (i = 0; i < dal_vector_get_count(&mm->solution_container_list);
+ ++i) {
+ struct display_view_solution_container *dvsc =
+ *(solution_container_vector_at_index(
+ &mm->solution_container_list,
+ i));
+ dal_dvsc_destroy(&dvsc);
+ }
+
+ dal_vector_destruct(&mm->solution_container_list);
+}
+
+void dal_mode_manager_destroy(struct mode_manager **mm)
+{
+ if (mm == NULL || *mm == NULL)
+ return;
+ destruct(*mm);
+
+ dal_free(*mm);
+ *mm = NULL;
+}
+
+/**
+ * patches view to be SLS-Compatible view
+ * for every non-4-divisible mode we want to have closest lower 8-divisible mode
+ */
+static bool patch_view_for_sls_compatibility(
+ struct mode_manager *mm,
+ struct view_info *vi)
+{
+ if (vi->view.width % mm->pixel_granularity != 0) {
+ vi->view.width -= vi->view.width % 8;
+ return true;
+ }
+
+ return false;
+}
+
+static bool construct(
+ struct mode_manager *mm,
+ const struct mode_manager_init_data *init_data)
+{
+ struct view min_view_override = { 0 };
+ struct view max_view_override = { 0 };
+ bool force_min_max_res = false;
+ uint32_t i;
+ uint32_t count;
+ const struct default_mode_list *default_modes;
+
+ if (!init_data)
+ return false;
+ if (!init_data->as)
+ return false;
+ if (!init_data->default_modes)
+ return false;
+
+ mm->ctx = init_data->dal_context;
+ mm->as = init_data->as;
+ mm->pixel_granularity =
+ dal_adapter_service_get_view_port_pixel_granularity(mm->as);
+
+ if (!dal_view_info_list_construct(&mm->master_view_list,
+ min_view_override, max_view_override, force_min_max_res))
+ return false;
+
+ for (i = 0; i < ARRAY_SIZE(guaranteed_view_info); i++)
+ dal_view_info_list_insert(
+ &mm->master_view_list, &guaranteed_view_info[i]);
+
+ /*
+ * populate master_view_list with views from default_mode_list
+ */
+ default_modes = init_data->default_modes;
+ count = dal_default_mode_list_get_count(default_modes);
+
+ for (i = 0; i < count; i++) {
+ const struct mode_info *mi =
+ dal_default_mode_list_get_mode_info_at_index(
+ default_modes, i);
+ struct view view = { mi->pixel_width, mi->pixel_height };
+ union adapter_view_importance importance = { 0 };
+ struct view_info cur_vi;
+ uint32_t index = 0;
+
+ importance.flags.OPTIONAL = mi->timing_source ==
+ TIMING_SOURCE_BASICMODE;
+ importance.flags.DEFAULT_VIEW = 1;
+
+ cur_vi.importance = importance;
+ cur_vi.view = view;
+
+ if (dal_view_info_list_find(
+ &mm->master_view_list, &cur_vi, &index))
+ /* view is already in the list, update importance */
+ dal_view_info_list_at_index(
+ &mm->master_view_list, index)->
+ importance.value |= importance.value;
+ else
+ if (!dal_view_info_list_insert(
+ &mm->master_view_list, &cur_vi))
+ dal_logger_write(mm->ctx->logger,
+ LOG_MAJOR_MODE_ENUM,
+ LOG_MINOR_MODE_ENUM_MASTER_VIEW_LIST,
+ "%s: one view is not inserted %dx%d\n",
+ __func__,
+ view.width,
+ view.height);
+ }
+
+ /*
+ * Add modified views for SLS
+ */
+ count = dal_view_info_list_get_count(&mm->master_view_list);
+ for (i = 0; i < count; ++i) {
+ struct view_info *vi_sls_compatible =
+ dal_view_info_list_at_index(&mm->master_view_list, i);
+
+ if (patch_view_for_sls_compatibility(mm, vi_sls_compatible))
+ dal_view_info_list_insert(
+ &mm->master_view_list, vi_sls_compatible);
+ }
+
+ dal_logger_write(mm->ctx->logger,
+ LOG_MAJOR_MODE_ENUM,
+ LOG_MINOR_MODE_ENUM_MASTER_VIEW_LIST,
+ "Master View List, %u views:\n",
+ dal_view_info_list_get_count(&mm->master_view_list));
+
+ if (!dal_vector_construct(
+ &mm->solution_container_list,
+ SOLUTION_CONTAINER_LIST_INITIAL_CAPACITY,
+ sizeof(struct display_view_solution_container *))) {
+ dal_view_info_list_destruct(&mm->master_view_list);
+ return false;
+ }
+
+ /* Check if Low Bitdepth (8bpp/16bpp) modes are required to be
+ * enumerated */
+ if (!dal_adapter_service_get_asic_runtime_flags(mm->as).bits.
+ NO_LOW_BPP_MODES) {
+ if (dal_adapter_service_is_feature_supported(
+ FEATURE_8BPP_SUPPORTED))
+ mm->supported_pixel_format |= PIXEL_FORMAT_INDEX8;
+
+ mm->supported_pixel_format |= PIXEL_FORMAT_RGB565;
+ }
+
+ mm->supported_pixel_format |= PIXEL_FORMAT_ARGB8888;
+ mm->supported_pixel_format |= PIXEL_FORMAT_ARGB2101010;
+
+ if (dal_adapter_service_get_asic_runtime_flags(mm->as).bits.
+ SUPPORT_XRBIAS)
+ mm->supported_pixel_format |=
+ PIXEL_FORMAT_ARGB2101010_XRBIAS;
+
+ mm->supported_pixel_format |= PIXEL_FORMAT_FP16;
+
+ return true;
+}
+
+static struct display_view_solution_container *create_association_table(
+ struct mode_manager *mm, uint32_t display_index)
+{
+ struct display_view_solution_container *tbl;
+ union best_view_flags flags = {};
+ struct display_view_solution_container_init_data dvsc_init_data = {
+ .ds_dispatch = mm->ds_dispatch,
+ .display_index = display_index,
+ .master_view_list = &mm->master_view_list,
+ .capacity = dal_flat_set_capacity(&mm->master_view_list.set),
+ .dal_context = mm->ctx,
+ };
+ flags.bits.PREFER_3D_TIMING = dal_adapter_service_is_feature_supported(
+ FEATURE_PREFER_3D_TIMING);
+ dvsc_init_data.bv_flags = flags;
+
+ tbl = dal_dvsc_create(&dvsc_init_data);
+
+ if (!tbl)
+ return NULL;
+
+ if (!solution_container_vector_append(
+ &mm->solution_container_list,
+ &tbl)) {
+ dal_dvsc_destroy(&tbl);
+ return NULL;
+ }
+ return tbl;
+}
+
+/**
+ * maps display path to view to timing association.
+ * if association table already exist, return pointer to association table.
+ * otherwise, create a new association table for this display path and added to
+ * association master table.
+ *
+ * pointer to display_view_solution_container of given display_path
+ */
+
+
+static struct display_view_solution_container *get_association_table(
+ struct mode_manager *mm, uint32_t display_index)
+{
+ uint32_t i;
+ uint32_t scl_size = dal_vector_get_count(&mm->solution_container_list);
+
+ dal_logger_write(mm->ctx->logger,
+ LOG_MAJOR_MODE_ENUM,
+ LOG_MINOR_MODE_ENUM_MASTER_VIEW_LIST,
+ "%s: display_index:%d, solution container size: %d\n",
+ __func__, display_index, scl_size);
+
+ for (i = 0; i < scl_size; i++) {
+ struct display_view_solution_container *item =
+ *(solution_container_vector_at_index(
+ &mm->solution_container_list,
+ i));
+
+ if (item->display_index == display_index)
+ return item;
+ }
+
+ return create_association_table(mm, display_index);
+}
+
+struct mode_query *dal_mode_manager_create_mode_query(
+ struct mode_manager *mm,
+ const struct topology *topology,
+ const enum query_option option)
+{
+ struct mode_query *mq;
+ struct mode_query_init_data mq_init_data = {0};
+ struct mode_query_set_init_data mqs_init_data = {0};
+
+ uint32_t i;
+
+ if (topology == NULL) {
+ dal_logger_write(mm->ctx->logger,
+ LOG_MAJOR_MODE_ENUM,
+ LOG_MINOR_MODE_ENUM_MASTER_VIEW_LIST,
+ "%s - Invalid parameter\n", __func__);
+ BREAK_TO_DEBUGGER();
+ return NULL;
+ }
+
+ mqs_init_data.ctx = mm->ctx;
+ mqs_init_data.supported_pixel_format = mm->supported_pixel_format;
+ mqs_init_data.master_view_list = &mm->master_view_list;
+
+ mq_init_data.ctx = mm->ctx;
+ mq_init_data.ds_dispatch = mm->ds_dispatch;
+ mq_init_data.query_set = dal_mode_query_set_create(&mqs_init_data);
+
+ if (!mq_init_data.query_set) {
+ dal_logger_write(mm->ctx->logger,
+ LOG_MAJOR_MODE_ENUM,
+ LOG_MINOR_MODE_ENUM_MASTER_VIEW_LIST,
+ "%s - Mode query set was not created\n", __func__);
+ return NULL;
+ }
+
+ for (i = 0; i < topology->disp_path_num; i++) {
+ if (!(dal_mode_query_set_add_solution_container(
+ mq_init_data.query_set,
+ get_association_table(
+ mm,
+ topology->display_index[i])))) {
+ dal_logger_write(mm->ctx->logger,
+ LOG_MAJOR_MODE_ENUM,
+ LOG_MINOR_MODE_ENUM_MASTER_VIEW_LIST,
+ " %s:%d: Container is invalid\n",
+ __func__, __LINE__);
+ goto free_mode_query_set;
+ }
+ }
+
+ switch (option) {
+ case QUERY_OPTION_NO_PAN:
+ if (topology->disp_path_num > 2)
+ mq = dal_mode_query_wide_topology_create(&mq_init_data);
+ else
+ mq = dal_mode_query_no_pan_create(&mq_init_data);
+ break;
+
+ case QUERY_OPTION_NO_PAN_NO_DISPLAY_VIEW_RESTRICTION:
+ mq = dal_mode_query_no_pan_no_display_view_restriction_create(
+ &mq_init_data);
+ break;
+
+ case QUERY_OPTION_3D_LIMITED_CANDIDATES:
+ if (topology->disp_path_num > 2)
+ mq =
+ dal_mode_query_3d_limited_cand_wide_topology_create(
+ &mq_init_data);
+ else
+ mq = dal_mode_query_3d_limited_candidates_create(
+ &mq_init_data);
+ break;
+
+ case QUERY_OPTION_PAN_ON_LIMITED_RESOLUTION_DISP_PATH:
+ mq = dal_mode_query_pan_on_limited_create(&mq_init_data);
+ break;
+
+ case QUERY_OPTION_ALLOW_PAN:
+ mq = dal_mode_query_allow_pan_create(&mq_init_data);
+ break;
+ case QUERY_OPTION_ALLOW_PAN_NO_VIEW_RESTRICTION:
+ mq = dal_mode_query_allow_pan_no_view_restriction_create(
+ &mq_init_data);
+ break;
+
+ case QUERY_OPTION_TILED_DISPLAY_PREFERRED:
+ mq = dal_mode_query_tiled_display_preferred_create(
+ &mq_init_data);
+ break;
+ default:
+ goto free_mode_query_set;
+ }
+
+ if (mq == NULL)
+ goto free_mode_query_set;
+
+ if (option == QUERY_OPTION_PAN_ON_LIMITED_RESOLUTION_DISP_PATH ||
+ option == QUERY_OPTION_ALLOW_PAN ||
+ option == QUERY_OPTION_ALLOW_PAN_NO_VIEW_RESTRICTION)
+
+ dal_mode_query_allow_pan_post_initialize(mq);
+
+ return mq;
+free_mode_query_set:
+ dal_mode_query_set_destroy(&mq_init_data.query_set);
+ return NULL;
+}
+
+bool dal_mode_manager_retreive_path_mode_set(
+ struct mode_manager *mm,
+ struct path_mode_set *path_mode_set,
+ struct render_mode *render_mode,
+ struct refresh_rate *refresh_rate,
+ const struct topology *top,
+ enum query_option option,
+ bool allow_fallback)
+{
+ struct mode_query *mode_query = dal_mode_manager_create_mode_query(
+ mm,
+ top,
+ option);
+ dal_mode_query_destroy(&mode_query);
+ return false;
+ /* TODO to be implemented */
+}
+
+struct mode_manager *dal_mode_manager_create(
+ const struct mode_manager_init_data *init_data)
+{
+ struct mode_manager *mm = dal_alloc(sizeof(struct mode_manager));
+
+ if (!mm)
+ return NULL;
+
+ if (construct(mm, init_data))
+ return mm;
+
+ BREAK_TO_DEBUGGER();
+ dal_free(mm);
+
+ return NULL;
+}
+
+uint32_t dal_mode_manager_get_supported_pixel_format(
+ const struct mode_manager *mm)
+{
+ return mm->supported_pixel_format;
+}
+
+void dal_mode_manager_set_supported_pixel_format(
+ struct mode_manager *mm,
+ uint32_t supported_pixel_format_mask)
+{
+ mm->supported_pixel_format = supported_pixel_format_mask;
+}
+
+struct bestview_options dal_mode_manager_get_bestview_options(
+ struct mode_manager *mm,
+ uint32_t display_index)
+{
+ struct bestview_options options;
+
+ struct display_view_solution_container *tbl =
+ get_association_table(mm, display_index);
+ if (tbl)
+ options = dal_dvsc_get_bestview_options(tbl);
+
+ return options;
+}
+
+static enum display_view_importance determine_display_view_importance(
+ struct dal_context *ctx,
+ enum timing_source timing_source, bool default_view)
+{
+ switch (timing_source) {
+ case TIMING_SOURCE_USER_FORCED:
+ case TIMING_SOURCE_DALINTERFACE_EXPLICIT:
+ case TIMING_SOURCE_EDID_DETAILED:
+ case TIMING_SOURCE_CV:
+ case TIMING_SOURCE_TV:
+ case TIMING_SOURCE_VBIOS:
+ case TIMING_SOURCE_USER_OVERRIDE:
+ case TIMING_SOURCE_EDID_CEA_SVD_3D:
+ case TIMING_SOURCE_HDMI_VIC:
+ return DISPLAY_VIEW_IMPORTANCE_GUARANTEED;
+ case TIMING_SOURCE_EDID_ESTABLISHED:
+ case TIMING_SOURCE_EDID_STANDARD:
+ case TIMING_SOURCE_EDID_CEA_SVD:
+ case TIMING_SOURCE_EDID_CVT_3BYTE:
+ case TIMING_SOURCE_EDID_4BYTE:
+ return default_view ?
+ DISPLAY_VIEW_IMPORTANCE_OPTIONAL :
+ DISPLAY_VIEW_IMPORTANCE_NON_GUARANTEED;
+ case TIMING_SOURCE_OS_FORCED:
+ case TIMING_SOURCE_DALINTERFACE_IMPLICIT:
+ case TIMING_SOURCE_DEFAULT:
+ case TIMING_SOURCE_CUSTOM:
+ case TIMING_SOURCE_CUSTOM_BASE:
+ return DISPLAY_VIEW_IMPORTANCE_RESTRICTED;
+ case TIMING_SOURCE_RANGELIMIT:
+ return DISPLAY_VIEW_IMPORTANCE_NON_GUARANTEED;
+ default:
+ /* MM doesn't handle this timing source!!! */
+ dal_logger_write(ctx->logger,
+ LOG_MAJOR_MODE_ENUM,
+ LOG_MINOR_MODE_ENUM_MASTER_VIEW_LIST,
+ "%s: timing source is incorrect: %d\n",
+ __func__,
+ timing_source);
+ return DISPLAY_VIEW_IMPORTANCE_NON_GUARANTEED;
+ }
+}
+
+#define ALLOC_RESERVE_CNT 16
+
+static bool grow_all_tables(struct mode_manager *mm)
+{
+ uint32_t capacity = dal_view_info_list_get_count(&mm->master_view_list)
+ + ALLOC_RESERVE_CNT;
+ uint32_t i;
+ uint32_t scl_count = dal_vector_get_count(&mm->solution_container_list);
+
+ for (i = 0; i < scl_count; ++i) {
+ struct display_view_solution_container *dvsc =
+ *(solution_container_vector_at_index(
+ &mm->solution_container_list, i));
+ if (!dvsc) {
+ dal_logger_write(mm->ctx->logger,
+ LOG_MAJOR_MODE_ENUM,
+ LOG_MINOR_MODE_ENUM_MASTER_VIEW_LIST,
+ " %s:%d: dvsc is NULL\n", __func__, __LINE__);
+ return false;
+ }
+ if (!dal_dvsc_grow(dvsc, capacity))
+ return false;
+ }
+
+ if (!dal_view_info_list_reserve(&mm->master_view_list, capacity))
+ return false;
+ return true;
+}
+
+static bool insert_view_and_update_solutions(
+ struct mode_manager *mm,
+ const struct view_info *vi,
+ uint32_t *index)
+{
+ uint32_t j;
+ uint32_t solution_container_count;
+
+ if (dal_view_info_list_get_count(&mm->master_view_list) >=
+ dal_view_info_list_capacity(&mm->master_view_list))
+ if (!grow_all_tables(mm))
+ return false;
+
+ /* this is newly added view, insert the View to master view list, and
+ * insert association to all association tables. */
+ if (!dal_view_info_list_insert(&mm->master_view_list, vi))
+ /*
+ * failed to insert the view due to pruning against
+ * runtime parameters
+ */
+ return false;
+
+ solution_container_count =
+ dal_vector_get_count(&mm->solution_container_list);
+
+ for (j = 0; j < solution_container_count; ++j) {
+ /* set dispView flag on this display */
+ struct display_view_solution_container *dvsc =
+ *(solution_container_vector_at_index(
+ &mm->solution_container_list, j));
+ dal_dvsc_notify_newly_inserted_view_at_index(
+ dvsc, *index);
+ }
+
+ return true;
+}
+
+/**
+ * Adds view to master table or verifies it already exists there.
+ * In any case the view will be marked as display view
+ */
+static void add_display_view(
+ struct mode_manager *mm,
+ struct display_view_solution_container *tbl,
+ struct view_info *vi,
+ enum timing_source source)
+{
+ uint32_t index = 0;
+
+ if (dal_view_info_list_find(&mm->master_view_list, vi, &index) ||
+ insert_view_and_update_solutions(mm, vi, &index)) {
+ enum display_view_importance importance;
+ bool default_view =
+ dal_view_info_list_at_index(
+ &mm->master_view_list,
+ index)->
+ importance.flags.DEFAULT_VIEW;
+ dal_view_info_list_at_index(&mm->master_view_list, index)->
+ importance.value |= vi->importance.value;
+ importance = determine_display_view_importance(mm->ctx,
+ source, default_view);
+
+ dal_dvsc_update_view_importance(
+ tbl, index, importance);
+ }
+}
+
+static void process_display_views(
+ struct mode_manager *mm,
+ struct display_view_solution_container *association_tbl,
+ const struct mode_timing_list *mode_timing_list)
+{
+ uint32_t i;
+ uint32_t mtl_count = dal_mode_timing_list_get_count(mode_timing_list);
+
+ for (i = 0; i < mtl_count; ++i) {
+ const struct mode_timing *mt =
+ dal_mode_timing_list_get_timing_at_index(
+ mode_timing_list, i);
+ struct view_info vi = {
+ { mt->mode_info.pixel_width,
+ mt->mode_info.pixel_height },
+ { 0 } };
+ enum timing_source timing_source = mt->mode_info.timing_source;
+ /* Sometimes DAL will not enumerate a mode on a particular
+ * display unless it is part of a clone configuration. It will
+ * cause issue in some corner case when OS try to keep DFP
+ * single in the mode that supported in clone configuration. We
+ * add a W/A that if flag PREFERRED_VIEW is set for a mode,
+ * other displays will support it always */
+ if (mt->mode_info.flags.PREFERRED_VIEW)
+ vi.importance.flags.PREFERRED_VIEW = 1;
+
+ /* Add original view */
+ add_display_view(mm, association_tbl, &vi, timing_source);
+
+ /* Add modified views */
+
+ {
+ struct view_info vi_sls_compatible = vi;
+
+ if (patch_view_for_sls_compatibility(
+ mm, &vi_sls_compatible))
+ add_display_view(
+ mm,
+ association_tbl,
+ &vi_sls_compatible,
+ timing_source);
+ }
+ }
+}
+
+/**
+* validate the given set of ModeQuery for cofunctionality
+*
+* the mode_query may or may not have RenderMode/RefreshRate/Scaling selected.
+* If it's not selected then ModeMgr will try select the least resource consuming
+* configuration and use it to do validation
+*/
+bool dal_mode_mgr_are_mode_queries_cofunctional(
+ struct mode_manager *mm,
+ struct mode_query **mode_queries,
+ uint32_t count)
+{
+ /*
+ * set up ModeQueryValidator.
+ */
+ uint32_t i;
+ bool result = false;
+ struct mode_query *mode_query;
+ struct cofunctional_mode_query_validator *validator =
+ dal_cmqv_create(mm->ds_dispatch);
+
+ for (i = 0; i < count; ++i) {
+ mode_query = mode_queries[i];
+ if (!dal_cmqv_add_mode_query(validator, mode_query))
+ goto free_validator;
+ }
+
+ /* if mode query has something unpinned (unselected), select something
+ * and try validate. Below assumed that select min resource for auto
+ * selected is able to select path mode combination that uses the least
+ * resource for unpinned item,
+ * as well as there is only 1 combination. This may not be the case, as
+ * resource is not an absolute number, and there maybe multiple
+ * combination that below code need to select and try (i.e. higher pixel
+ * clock but no scaling vs lower pixel clock with scaling). This code is
+ * in a separate loop so we can address the problem of selecting and
+ * trying different combination if required.
+ */
+ for (i = 0; i < count; ++i) {
+ mode_query = mode_queries[i];
+
+ if (!dal_mode_query_select_min_resources_for_autoselect(
+ mode_query))
+ goto free_validator;
+
+ /* update the validator with the above selected combination */
+ dal_cmqv_update_mode_query(
+ validator, mode_query);
+ }
+
+ result = dal_cmqv_is_cofunctional(validator);
+free_validator:
+ dal_cmqv_destroy(&validator);
+ return result;
+}
+
+/*
+ * Updates (or create) association from master view list to associated timing &
+ * scaling. Method does the following
+ * 1. Update TS mode timing list on this disp index according to the DCS on this
+ * path
+ */
+bool dal_mode_manager_update_disp_path_func_view_tbl(
+ struct mode_manager *mm,
+ uint32_t display_index,
+ struct mode_timing_list *mtl)
+{
+ /* gets the association table of the given display path */
+ struct display_view_solution_container *tbl =
+ get_association_table(
+ mm,
+ display_index);
+
+ /* create new associate table if it doesn't exist already */
+ if (!tbl) {
+ dal_logger_write(mm->ctx->logger, LOG_MAJOR_MODE_ENUM,
+ LOG_MINOR_MODE_ENUM_TS_LIST_BUILD,
+ "%s: PathInd:%d: Display View Solution Container is NULL!\n",
+ __func__,
+ display_index);
+ return false;
+ }
+
+ if (!mtl) {
+ dal_logger_write(mm->ctx->logger, LOG_MAJOR_MODE_ENUM,
+ LOG_MINOR_MODE_ENUM_TS_LIST_BUILD,
+ "TS::ModeTimingList(%d) not initialized yet.\n",
+ display_index);
+ return false;
+ }
+
+ /* update given container with given best view option with views in
+ * master view list */
+ if (!dal_dvsc_update(tbl, mtl)) {
+ dal_logger_write(mm->ctx->logger, LOG_MAJOR_MODE_ENUM,
+ LOG_MINOR_MODE_ENUM_TS_LIST_BUILD,
+ "%s: PathInd:%d: failed to update container with best view!\n",
+ __func__,
+ display_index);
+ return false;
+ }
+
+ /* add views explicitly supported by this display but not in
+ * master view list and update associations for all displays on these
+ * newly added views. Mark views explicitly supported by this display in
+ * association table
+ */
+ process_display_views(mm, tbl, mtl);
+
+ return true;
+}
+
+struct bestview_options dal_mode_manager_get_default_bestview_options(
+ struct mode_manager *mm,
+ uint32_t display_index)
+{
+ struct bestview_options options = { 0 };
+
+ struct display_view_solution_container *tbl = get_association_table(
+ mm, display_index);
+
+ if (tbl)
+ options = dal_dvsc_get_default_bestview_options(tbl);
+
+ return options;
+}
+
+void dal_mode_manager_set_bestview_options(
+ struct mode_manager *mm,
+ uint32_t display_index,
+ const struct bestview_options *opts,
+ bool rebuild_bestview,
+ struct mode_timing_list *mtl)
+{
+ struct display_view_solution_container *tbl;
+
+ if (!opts)
+ return;
+
+ tbl = get_association_table(mm, display_index);
+
+ if (!tbl)
+ return;
+
+ dal_dvsc_save_bestview_options(tbl, opts);
+
+ if (rebuild_bestview)
+ dal_mode_manager_update_disp_path_func_view_tbl(
+ mm, display_index, mtl);
+}
+
+void dal_mode_manager_set_ds_dispatch(
+ struct mode_manager *mm,
+ struct ds_dispatch *ds_dispatch)
+{
+ mm->ds_dispatch = ds_dispatch;
+}
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/mode_manager_types.c b/drivers/gpu/drm/amd/dal/mode_manager/mode_manager_types.c
new file mode 100644
index 000000000000..1e4c44b86063
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/mode_manager_types.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dal_services.h"
+#include "include/mode_manager_types.h"
+
+bool dal_refresh_rate_is_equal(
+ const struct refresh_rate *lhs,
+ const struct refresh_rate *rhs)
+{
+ return lhs->field_rate == rhs->field_rate &&
+ lhs->INTERLACED == rhs->INTERLACED &&
+ lhs->VIDEO_OPTIMIZED_RATE == rhs->VIDEO_OPTIMIZED_RATE;
+}
+
+void refresh_rate_from_mode_info(
+ struct refresh_rate *rf,
+ const struct mode_info *mode_info)
+{
+ rf->field_rate = mode_info->field_rate;
+ rf->INTERLACED = mode_info->flags.INTERLACE;
+ rf->VIDEO_OPTIMIZED_RATE = mode_info->flags.VIDEO_OPTIMIZED_RATE;
+}
+
+bool dal_refresh_rate_less_than(
+ const struct refresh_rate *lhs,
+ const struct refresh_rate *rhs)
+{
+ unsigned int lhsRefreshRate;
+ unsigned int rhsRefreshRate;
+
+ lhsRefreshRate = lhs->INTERLACED ?
+ (lhs->field_rate / 2) : lhs->field_rate;
+ rhsRefreshRate = rhs->INTERLACED ?
+ (rhs->field_rate / 2) : rhs->field_rate;
+
+ if (lhsRefreshRate != rhsRefreshRate)
+ return lhsRefreshRate < rhsRefreshRate;
+
+ /* interlaced < progressive */
+ if (lhs->INTERLACED != rhs->INTERLACED)
+ return lhs->INTERLACED > rhs->INTERLACED;
+
+ /* videoOptimizedRate (refreshrate/1.001)
+ * < non videoOptimizedRate (refreshrate/1.000) */
+ return lhs->VIDEO_OPTIMIZED_RATE > rhs->VIDEO_OPTIMIZED_RATE;
+}
+
+bool dal_solution_less_than(const void *lhs, const void *rhs)
+{
+ const struct solution *lhs_solution = lhs;
+ const struct solution *rhs_solution = rhs;
+ struct refresh_rate l_refresh_rate, r_refresh_rate;
+ enum timing_3d_format l_timing_3d_format, r_timing_3d_format;
+
+ refresh_rate_from_mode_info(
+ &l_refresh_rate,
+ &lhs_solution->mode_timing->mode_info);
+ refresh_rate_from_mode_info(
+ &r_refresh_rate,
+ &rhs_solution->mode_timing->mode_info);
+ if (dal_refresh_rate_less_than(&l_refresh_rate, &r_refresh_rate))
+ return true;
+ else if (dal_refresh_rate_less_than(&r_refresh_rate, &l_refresh_rate))
+ return false;
+
+ l_timing_3d_format = lhs_solution->mode_timing->
+ crtc_timing.timing_3d_format;
+ r_timing_3d_format = rhs_solution->mode_timing->
+ crtc_timing.timing_3d_format;
+ if (l_timing_3d_format != r_timing_3d_format)
+ return l_timing_3d_format < r_timing_3d_format;
+
+ return lhs_solution->mode_timing->mode_info.timing_source <
+ rhs_solution->mode_timing->mode_info.timing_source;
+}
+
+bool dal_view_is_equal(const struct view *lhs, const struct view *rhs)
+{
+ return lhs->height == rhs->height && lhs->width == rhs->width;
+}
+
+uint32_t dal_pixel_format_list_get_count(
+ const struct pixel_format_list *pfl)
+{
+ uint32_t i, count = 0;
+
+ for (i = pfl->set; i > 0; i >>= 1)
+ if ((i & 1) != 0)
+ count += 1;
+ return count;
+}
+
+enum pixel_format dal_pixel_format_list_get_pixel_format(
+ const struct pixel_format_list *pfl)
+{
+ return least_significant_bit(pfl->iter.value);
+}
+
+void dal_pixel_format_list_reset_iterator(struct pixel_format_list *pfl)
+{
+ bit_set_iterator_reset_to_mask(&pfl->iter, pfl->set);
+}
+
+void dal_pixel_format_list_zero_iterator(struct pixel_format_list *pfl)
+{
+ bit_set_iterator_reset_to_mask(&pfl->iter, 0);
+}
+
+enum pixel_format dal_pixel_format_list_next(struct pixel_format_list *pfl)
+{
+ return get_next_significant_bit(&pfl->iter);
+}
+
+void dal_pixel_format_list_construct(
+ struct pixel_format_list *pfl,
+ uint32_t mask)
+{
+ bit_set_iterator_construct(&pfl->iter, mask);
+ pfl->set = mask;
+}
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/mode_query.c b/drivers/gpu/drm/amd/dal/mode_manager/mode_query.c
new file mode 100644
index 000000000000..e6d03b3d7c8d
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/mode_query.c
@@ -0,0 +1,785 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dal_services.h"
+#include "mode_query.h"
+#include "include/set_mode_types.h"
+#include "include/mode_manager_types.h"
+#include "include/logger_interface.h"
+
+void dal_mode_query_destruct(struct mode_query *mq)
+{
+ dal_cofunctional_mode_validator_destruct(&mq->validator);
+ dal_mode_query_set_destroy(&mq->query_set);
+}
+
+bool dal_mode_query_construct(
+ struct mode_query *mq,
+ struct mode_query_init_data *mq_init_data)
+{
+ uint32_t i;
+ struct path_mode path_mode = { { 0 } };
+ bool top_contain_16x9_disp = false;
+ bool top_contain_16x10_disp = false;
+
+ mq->supported_scl_for_3d_mode = 0;
+ if (mq_init_data->query_set == NULL)
+ return false;
+ mq->query_set = mq_init_data->query_set;
+ if (!dal_cofunctional_mode_validator_construct(
+ &mq->validator,
+ mq_init_data->ds_dispatch))
+ return false;
+
+ mq->is_valid = false;
+
+ for (i = 0; i < mq->query_set->num_path; i++) {
+ enum mode_aspect_ratio aspect;
+
+ path_mode.display_path_index =
+ mode_query_set_get_solution_container_on_path(
+ mq->query_set,
+ i)->display_index;
+
+ if (!dal_pms_add_path_mode(
+ mq->validator.pms,
+ &path_mode))
+ dal_logger_write(mq_init_data->ctx->logger,
+ LOG_MAJOR_MODE_ENUM,
+ LOG_MINOR_MODE_ENUM_MASTER_VIEW_LIST,
+ "invalid topology");
+
+ mq->topology.display_index[i] = path_mode.display_path_index;
+
+ aspect = mode_query_set_get_solution_container_on_path(
+ mq->query_set, i)->mode_aspect_ratio;
+ switch (aspect) {
+ case MODE_ASPECT_RATIO_16X9:
+ top_contain_16x9_disp = true;
+ break;
+ case MODE_ASPECT_RATIO_16X10:
+ top_contain_16x10_disp = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ mq->topology.disp_path_num = mq->query_set->num_path;
+
+ if (dal_pms_get_path_mode_num(mq->validator.pms) !=
+ mq->query_set->num_path)
+ dal_logger_write(mq_init_data->ctx->logger,
+ LOG_MAJOR_MODE_ENUM,
+ LOG_MINOR_MODE_ENUM_MASTER_VIEW_LIST,
+ " %s:%d: number of pathes should be equal",
+ __func__,
+ __LINE__);
+
+ mq->enum_adapter_view_match.flags.GUARANTEED = 1;
+ mq->enum_adapter_view_match.flags.GUARANTEED_16X9 =
+ top_contain_16x9_disp;
+ mq->enum_adapter_view_match.flags.GUARANTEED_16X10 =
+ top_contain_16x10_disp;
+
+ switch (mq->query_set->num_path) {
+ case 1:
+ mq->enum_adapter_view_match.flags.OPTIONAL = 1;
+ mq->enum_adapter_view_match.flags.PREFERRED_VIEW = 1;
+
+ mq->enum_display_view_level =
+ DISPLAY_VIEW_IMPORTANCE_RESTRICTED;
+ mq->enum_solution_importance = SOLUTION_IMPORTANCE_UNSAFE;
+
+ break;
+ case 2:
+ mq->enum_adapter_view_match.flags.OPTIONAL = 1;
+ mq->enum_display_view_level = DISPLAY_VIEW_IMPORTANCE_OPTIONAL;
+ mq->enum_solution_importance = SOLUTION_IMPORTANCE_SAFE;
+
+ break;
+ default:
+ mq->enum_display_view_level =
+ DISPLAY_VIEW_IMPORTANCE_GUARANTEED;
+ mq->enum_solution_importance = SOLUTION_IMPORTANCE_SAFE;
+ break;
+ }
+
+ if (mq->query_set->num_path == 1) {
+ struct mode_enum_override override =
+ mode_query_set_get_solution_container_on_path(
+ mq->query_set,
+ 0)->
+ best_view->mode_enum_override;
+
+ if (override.RESTRICT_ADAPTER_VIEW)
+ mq->enum_adapter_view_match.value = 0;
+
+ if (override.ALLOW_ONLY_BEST_VIEW_OVERRIDE_DISPLAY_VIEW)
+ mq->enum_display_view_level =
+ DISPLAY_VIEW_IMPORTANCE_BESTVIEW_OVERRIDE;
+ }
+
+ mq->supported_scl_for_3d_mode = UINT_MAX;
+ mq->solution_filter.raw = 0;
+ return true;
+}
+
+void dal_mode_query_destroy(struct mode_query **mq)
+{
+ if (!mq || !*mq)
+ return;
+ (*mq)->funcs->destroy(*mq);
+ dal_free(*mq);
+ *mq = NULL;
+}
+
+bool dal_mode_query_pin_path_mode(
+ struct mode_query *mq,
+ const struct path_mode *path_mode)
+{
+ return dal_pms_add_path_mode(
+ mq->validator.pms,
+ path_mode);
+}
+
+const struct render_mode *dal_mode_query_get_current_render_mode(
+ const struct mode_query *mq)
+{
+ return mq->is_valid ? &mq->cur_render_mode : NULL;
+}
+
+const struct stereo_3d_view *dal_mode_query_get_current_3d_view(
+ const struct mode_query *mq)
+{
+ return mq->is_valid ? &mq->cur_stereo_3d_view : NULL;
+}
+
+const struct refresh_rate *dal_mode_query_get_current_refresh_rate(
+ const struct mode_query *mq)
+{
+ const struct refresh_rate *cur_cofunc_rf = NULL;
+
+ if (mq->is_valid &&
+ mq->query_set->num_path > mq->cur_path_idx_for_cofunc_rf)
+ cur_cofunc_rf = &mq->
+ cur_refresh_rates[
+ mq->cur_path_idx_for_cofunc_rf];
+
+ return cur_cofunc_rf;
+}
+
+const struct path_mode_set *dal_mode_query_get_current_path_mode_set(
+ const struct mode_query *mq)
+{
+ return mq->is_valid ? mq->validator.pms : NULL;
+}
+
+static void update_cur_render_mode(struct mode_query *mq)
+{
+ dal_memmove(
+ &mq->cur_render_mode.view,
+ mode_query_set_get_view_at_index(
+ mq->query_set,
+ mq->cur_view_idx),
+ sizeof(struct view));
+
+ mq->cur_render_mode.pixel_format =
+ dal_pixel_format_list_get_pixel_format(
+ &mq->query_set->
+ pixel_format_list_iterator);
+}
+
+static bool increment_cofunc_3d_view_it(struct mode_query *mq)
+{
+ mq->valid_iterators.COFUNC_3D_VIEW = false;
+
+ /* New iteration - start from the beginning*/
+ if (mq->cur_view_3d_format == VIEW_3D_FORMAT_COUNT) {
+ mq->cur_view_3d_format = VIEW_3D_FORMAT_NONE;
+ mq->valid_iterators.COFUNC_3D_VIEW = true;
+ } else if (mq->cur_view_3d_format + 1 < VIEW_3D_FORMAT_COUNT) {
+ mq->cur_view_3d_format = mq->cur_view_3d_format + 1;
+ mq->valid_iterators.COFUNC_3D_VIEW = true;
+ }
+
+ return mq->valid_iterators.COFUNC_3D_VIEW;
+}
+
+void increment_cofunc_view_solution_it(struct mode_query *mq)
+{
+ uint32_t i;
+
+ for (i = 0; i < mq->query_set->num_path; i++) {
+ struct view_solution *vs;
+ uint32_t vs_count;
+
+ if (mq->cur_path_idx_for_cofunc_rf >= mq->query_set->num_path)
+ continue;
+
+ vs = &mq->cur_view_solutions[i];
+ vs_count = view_solution_get_count(vs);
+
+ if (mq->cur_solution_idxs[i] >= vs_count)
+ continue;
+
+ if (dal_refresh_rate_is_equal(
+ &mq->cur_refresh_rates[i],
+ &mq->cur_refresh_rates[mq->cur_path_idx_for_cofunc_rf]))
+ mq->cur_solution_idxs[i]++;
+ }
+}
+
+static bool increment_cofunc_scaling_support_it(struct mode_query *mq)
+{
+ int32_t i;
+
+ for (i = mq->query_set->num_path - 1; i >= 0; i--) {
+ for (mq->cofunc_scl[i]++;
+ *mq->cofunc_scl[i] != SCALING_TRANSFORMATION_INVALID;
+ mq->cofunc_scl[i]++) {
+ if (mq->cur_3d_views[i].view_3d_format !=
+ VIEW_3D_FORMAT_NONE &&
+ (mq->supported_scl_for_3d_mode &
+ *mq->cofunc_scl[i]) == 0)
+ continue;
+
+ mq->valid_iterators.COFUNC_SCALING_SUPPORT = true;
+ return true;
+ }
+
+ mq->cofunc_scl[i] =
+ mode_query_set_get_solution_container_on_path(
+ mq->query_set, i)->scl_enum_order_list;
+ }
+ mq->valid_iterators.COFUNC_SCALING_SUPPORT = false;
+ return false;
+}
+
+static bool is_cofunc_view_solution_it_in_range(struct mode_query *mq)
+{
+ uint32_t i;
+ uint32_t valid_solution_idx_cnt;
+ bool all_has_solution;
+
+ for (i = 0; i < mq->query_set->num_path; i++) {
+ struct view_solution *vs = &mq->cur_view_solutions[i];
+ uint32_t view_solution_count = view_solution_get_count(vs);
+
+ while (mq->cur_solution_idxs[i] < view_solution_count) {
+ bool strict_match_3d_view;
+ const struct crtc_timing *crtc_timing;
+ const struct solution *solution =
+ view_solution_get_solution_at_index(
+ vs,
+ mq->cur_solution_idxs[i]);
+ enum solution_importance cur_solution_importance =
+ solution->importance;
+
+ if (cur_solution_importance >
+ mq->enum_solution_importance) {
+ mq->cur_solution_idxs[i]++;
+ continue;
+ }
+
+ crtc_timing = &solution->mode_timing->crtc_timing;
+ strict_match_3d_view =
+ crtc_timing->flags.USE_IN_3D_VIEW_ONLY ||
+ crtc_timing->flags.EXCLUSIVE_3D ||
+ crtc_timing->flags.STEREO_3D_PREFERENCE;
+
+ if (strict_match_3d_view &&
+ mq->cur_view_3d_format != dvsc_get_stereo_3d_support(
+ mode_query_set_get_solution_container_on_path(
+ mq->query_set, i),
+ crtc_timing->timing_3d_format).format) {
+ mq->cur_solution_idxs[i]++;
+ continue;
+ }
+ mq->cur_solutions[i] = solution;
+ refresh_rate_from_mode_info(
+ &mq->cur_refresh_rates[i],
+ &mq->cur_solutions[i]->mode_timing->mode_info);
+ break;
+ }
+ }
+
+ valid_solution_idx_cnt = 0;
+ all_has_solution = true;
+
+ for (i = 0; i < mq->query_set->num_path; i++) {
+ struct view_solution *vs = &mq->cur_view_solutions[i];
+
+ if (mq->cur_solutions[i] == NULL) {
+ all_has_solution = false;
+ break;
+ }
+
+ if (mq->cur_solution_idxs[i] >= view_solution_get_count(vs))
+ continue;
+
+ if (valid_solution_idx_cnt == 0 ||
+ dal_refresh_rate_less_than(
+ &mq->cur_refresh_rates[i],
+ &mq->cur_refresh_rates
+ [mq->cur_path_idx_for_cofunc_rf]))
+ mq->cur_path_idx_for_cofunc_rf = i;
+
+ valid_solution_idx_cnt++;
+ }
+
+ mq->valid_iterators.COFUNC_VIEW_SOLUTION = all_has_solution &&
+ valid_solution_idx_cnt > 0;
+
+ return mq->valid_iterators.COFUNC_VIEW_SOLUTION;
+}
+
+static bool is_cur_3d_view_valid(struct mode_query *mq)
+{
+ uint32_t i;
+ uint32_t num_paths = mq->query_set->num_path;
+ bool valid = false;
+
+ stereo_3d_view_reset(&mq->cur_stereo_3d_view);
+
+ if (mq->cur_view_3d_format == VIEW_3D_FORMAT_NONE)
+ return true;
+
+ for (i = 0; i < num_paths; i++) {
+ const struct crtc_timing *crtc_timing =
+ &mq->cur_solutions[i]->mode_timing->crtc_timing;
+ struct view_stereo_3d_support stereo_3d_support =
+ dvsc_get_stereo_3d_support(
+ mode_query_set_get_solution_container_on_path(
+ mq->query_set, i),
+ crtc_timing->timing_3d_format);
+
+ stereo_3d_view_reset(&mq->cur_3d_views[i]);
+
+ if (stereo_3d_support.format != mq->cur_view_3d_format)
+ continue;
+
+ if (mq->solution_filter.bits.NO_CUSTOM_3D_MODES
+ && mq->cur_solutions[i]->is_custom_mode)
+ continue;
+
+ if (!stereo_3d_support.features.CLONE_MODE && num_paths > 1)
+ continue;
+
+ if (!stereo_3d_support.features.SCALING) {
+ uint32_t pixel_repetition =
+ crtc_timing->flags.PIXEL_REPETITION == 0 ? 1 :
+ crtc_timing->flags.PIXEL_REPETITION;
+ uint32_t pixel_width =
+ crtc_timing->h_addressable / pixel_repetition;
+ uint32_t pixel_height = crtc_timing->v_addressable;
+
+ if (mq->cur_render_mode.view.width != pixel_width ||
+ mq->cur_render_mode.view.height != pixel_height)
+ continue;
+ }
+
+ valid = true;
+
+ mq->cur_3d_views[i].view_3d_format = mq->cur_view_3d_format;
+ mq->cur_3d_views[i].flags.bits.SINGLE_FRAME_SW_PACKED =
+ stereo_3d_support.features.SINGLE_FRAME_SW_PACKED;
+ mq->cur_3d_views[i].flags.bits.EXCLUSIVE_3D =
+ crtc_timing->flags.EXCLUSIVE_3D;
+
+ mq->cur_stereo_3d_view.view_3d_format = mq->cur_view_3d_format;
+ mq->cur_stereo_3d_view.flags.bits.SINGLE_FRAME_SW_PACKED |=
+ mq->cur_3d_views[i].flags.bits.SINGLE_FRAME_SW_PACKED;
+ mq->cur_stereo_3d_view.flags.bits.EXCLUSIVE_3D |=
+ mq->cur_3d_views[i].flags.bits.EXCLUSIVE_3D;
+ }
+
+ return valid;
+}
+
+static void reset_cofunc_scaling_support_it(struct mode_query *mq)
+{
+ uint32_t i;
+
+ for (i = 0; i < mq->query_set->num_path; i++)
+ mq->cofunc_scl[i] =
+ mode_query_set_get_solution_container_on_path(
+ mq->query_set,
+ i)->scl_enum_order_list;
+
+ mq->cofunc_scl[mq->query_set->num_path - 1]--;
+ mq->valid_iterators.COFUNC_SCALING_SUPPORT = false;
+}
+
+void dal_mode_query_update_validator_entry(
+ struct mode_query *mq,
+ struct cofunctional_mode_validator *validator,
+ uint32_t validator_index,
+ uint32_t mode_query_index)
+{
+ bool is_guaranteed;
+
+ dal_memmove(
+ &cofunctional_mode_validator_get_at(
+ validator, validator_index)->view,
+ mq->cur_view_solutions[mode_query_index].view,
+ sizeof(struct view));
+
+ cofunctional_mode_validator_get_at(validator, validator_index)->
+ view_3d_format = mq->cur_3d_views[mode_query_index].view_3d_format;
+
+ cofunctional_mode_validator_get_at(validator, validator_index)->
+ pixel_format = dal_mode_query_set_get_pixel_format(mq->query_set);
+
+ cofunctional_mode_validator_get_at(validator, validator_index)->
+ mode_timing = mq->cur_solutions[mode_query_index]->mode_timing;
+
+ cofunctional_mode_validator_get_at(validator, validator_index)->
+ scaling = *mq->cofunc_scl[mode_query_index];
+
+ is_guaranteed = dal_solution_is_guaranteed(
+ mq->cur_solutions[mode_query_index],
+ mq->cur_render_mode.pixel_format,
+ *mq->cofunc_scl[mode_query_index]);
+
+ dal_cofunctional_mode_validator_flag_guaranteed_at(
+ validator,
+ validator_index,
+ is_guaranteed);
+}
+
+static void update_cur_path_mode_set(struct mode_query *mq)
+{
+ uint32_t i;
+
+ for (i = 0; i < mq->query_set->num_path; i++)
+ dal_mode_query_update_validator_entry(mq, &mq->validator, i, i);
+}
+
+static bool is_cur_scaling_valid(struct mode_query *mq)
+{
+ uint32_t i;
+
+ for (i = 0; i < mq->query_set->num_path; i++) {
+ if (!dal_solution_is_supported(
+ mq->cur_solutions[i],
+ mq->cur_render_mode.pixel_format,
+ *mq->cofunc_scl[i]))
+ return false;
+ }
+ return true;
+}
+
+bool dal_mode_query_base_select_next_scaling(struct mode_query *mq)
+{
+ if (!(mq->valid_iterators.RENDER_MODE
+ && mq->valid_iterators.COFUNC_3D_VIEW
+ && mq->valid_iterators.COFUNC_VIEW_SOLUTION)) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+
+ mq->is_valid = false;
+
+ while (!mq->is_valid && increment_cofunc_scaling_support_it(mq)) {
+ if (!is_cur_scaling_valid(mq))
+ continue;
+
+ update_cur_path_mode_set(mq);
+ mq->is_valid = dal_cofunctional_mode_validator_is_cofunctional(
+ &mq->validator);
+ }
+
+ return mq->is_valid;
+}
+
+bool dal_mode_query_select_next_scaling(struct mode_query *mq)
+{
+ return mq->funcs->select_next_scaling(mq);
+}
+
+bool dal_mode_query_select_next_refresh_rate(struct mode_query *mq)
+{
+ return mq->funcs->select_next_refresh_rate(mq);
+}
+
+bool dal_mode_query_base_select_next_refresh_rate(struct mode_query *mq)
+{
+ if (!(mq->valid_iterators.RENDER_MODE
+ && mq->valid_iterators.COFUNC_3D_VIEW)) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+
+ mq->is_valid = false;
+
+ for (increment_cofunc_view_solution_it(mq);
+ is_cofunc_view_solution_it_in_range(mq);
+ increment_cofunc_view_solution_it(mq)) {
+ if (!is_cur_3d_view_valid(mq))
+ continue;
+
+ reset_cofunc_scaling_support_it(mq);
+
+ if (dal_mode_query_select_next_scaling(mq))
+ break;
+ }
+
+ return mq->is_valid;
+}
+
+void dal_mode_query_reset_cofunc_view_solution_it(struct mode_query *mq)
+{
+ uint32_t i;
+
+ for (i = 0; i < mq->query_set->num_path; i++) {
+ mq->cur_solution_idxs[i] = 0;
+ mq->cur_solutions[i] = NULL;
+ }
+
+ mq->cur_path_idx_for_cofunc_rf = INVALID_VIEW_SOLUTION_INDEX;
+ mq->valid_iterators.COFUNC_VIEW_SOLUTION = false;
+}
+
+static bool select_next_view_3d_format(struct mode_query *mq)
+{
+ if (!mq->valid_iterators.RENDER_MODE) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+
+ mq->is_valid = false;
+
+ while (increment_cofunc_3d_view_it(mq)) {
+ dal_mode_query_reset_cofunc_view_solution_it(mq);
+ if (dal_mode_query_select_next_refresh_rate(mq))
+ break;
+ }
+
+ return mq->is_valid;
+}
+
+static void reset_confunc_3d_view_it(struct mode_query *mq)
+{
+ mq->valid_iterators.COFUNC_3D_VIEW = false;
+ dal_memset(&mq->cur_stereo_3d_view, 0, sizeof(struct stereo_3d_view));
+ mq->cur_stereo_3d_view.view_3d_format = VIEW_3D_FORMAT_NONE;
+ mq->cur_view_3d_format = VIEW_3D_FORMAT_COUNT;
+}
+
+static bool increment_render_mode_iterator(struct mode_query *mq)
+{
+ uint32_t view_count = dal_mode_query_set_get_view_count(mq->query_set);
+
+ dal_pixel_format_list_next(&mq->query_set->pixel_format_list_iterator);
+ if (dal_pixel_format_list_get_pixel_format(
+ &mq->query_set->pixel_format_list_iterator)) {
+ mq->valid_iterators.RENDER_MODE = true;
+ return true;
+ }
+
+ dal_pixel_format_list_reset_iterator(
+ &mq->query_set->pixel_format_list_iterator);
+ ++mq->cur_view_idx;
+ for (; mq->cur_view_idx < view_count; ++mq->cur_view_idx)
+ if (mq->funcs->build_cofunc_view_solution_set(mq))
+ break;
+ mq->valid_iterators.RENDER_MODE = mq->cur_view_idx < view_count;
+ return mq->valid_iterators.RENDER_MODE;
+}
+
+bool dal_mode_query_base_select_next_render_mode(struct mode_query *mq)
+{
+ mq->is_valid = false;
+
+ while (increment_render_mode_iterator(mq)) {
+ update_cur_render_mode(mq);
+
+ reset_confunc_3d_view_it(mq);
+
+ if (select_next_view_3d_format(mq))
+ break;
+ }
+ return mq->is_valid;
+}
+
+bool dal_mode_query_select_next_render_mode(struct mode_query *mq)
+{
+ return mq->funcs->select_next_render_mode(mq);
+}
+
+bool dal_mode_query_select_first(struct mode_query *mq)
+{
+ dal_pixel_format_list_zero_iterator(
+ &mq->query_set->pixel_format_list_iterator);
+ mq->cur_view_idx = INVALID_VIEW_SOLUTION_INDEX;
+ mq->valid_iterators.RENDER_MODE = false;
+ return dal_mode_query_select_next_render_mode(mq);
+}
+
+bool dal_mode_query_select_min_resources_for_autoselect(struct mode_query *mq)
+{
+ if (!mq->is_valid)
+ return dal_mode_query_select_first(mq);
+
+ return true;
+}
+
+bool dal_mode_query_select_render_mode(struct mode_query *mq,
+ const struct render_mode *render_mode)
+{
+ uint32_t vw_count = dal_mode_query_set_get_view_count(mq->query_set);
+ bool view_found = false;
+ bool found = false;
+
+ mq->valid_iterators.RENDER_MODE = false;
+
+ for (mq->cur_view_idx = 0;
+ mq->cur_view_idx < vw_count;
+ mq->cur_view_idx++)
+ if (dal_view_is_equal(
+ &render_mode->view,
+ mode_query_set_get_view_at_index(
+ mq->query_set,
+ mq->cur_view_idx))) {
+ view_found = true;
+ break;
+ }
+
+ if (view_found) {
+ if (render_mode->pixel_format != PIXEL_FORMAT_UNINITIALIZED) {
+ enum pixel_format fmt;
+
+ dal_pixel_format_list_reset_iterator(
+ &mq->query_set->pixel_format_list_iterator);
+ fmt = dal_pixel_format_list_get_pixel_format(
+ &mq->query_set->pixel_format_list_iterator);
+ while (PIXEL_FORMAT_UNINITIALIZED != fmt) {
+ if (render_mode->pixel_format == fmt) {
+ mq->valid_iterators.RENDER_MODE = true;
+ break;
+ }
+ dal_pixel_format_list_next(
+ &mq->query_set->
+ pixel_format_list_iterator);
+ fmt = dal_pixel_format_list_get_pixel_format(
+ &mq->query_set->
+ pixel_format_list_iterator);
+ }
+ } else
+ mq->valid_iterators.RENDER_MODE = true;
+ }
+
+ if (mq->valid_iterators.RENDER_MODE &&
+ mq->funcs->build_cofunc_view_solution_set(mq)) {
+ update_cur_render_mode(mq);
+ reset_confunc_3d_view_it(mq);
+ if (select_next_view_3d_format(mq))
+ found = true;
+ }
+
+ return found;
+}
+
+bool dal_mode_query_select_view_3d_format(
+ struct mode_query *mq,
+ enum view_3d_format format)
+{
+ if (!mq->valid_iterators.RENDER_MODE) {
+ BREAK_TO_DEBUGGER();
+ /* error in calling sequence, SelectNextView3DFormat is called
+ * without a valid render mode*/
+ return false;
+ }
+
+ mq->is_valid = false;
+
+ reset_confunc_3d_view_it(mq);
+
+ if (format < VIEW_3D_FORMAT_COUNT) {
+ mq->cur_view_3d_format = format;
+ mq->valid_iterators.COFUNC_3D_VIEW = true;
+
+ dal_mode_query_reset_cofunc_view_solution_it(mq);
+
+ if (dal_mode_query_select_next_refresh_rate(mq))
+ return true;
+ }
+
+ return false;
+}
+
+static const struct refresh_rate *get_current_refresh_rate(
+ const struct mode_query *mq)
+{
+ const struct refresh_rate *cur_cofunc_rf = NULL;
+
+ if (mq->is_valid &&
+ mq->cur_path_idx_for_cofunc_rf < mq->query_set->num_path)
+
+ cur_cofunc_rf = &mq->
+ cur_refresh_rates[mq->cur_path_idx_for_cofunc_rf];
+
+ return cur_cofunc_rf;
+}
+
+bool dal_mode_query_select_refresh_rate(struct mode_query *mq,
+ const struct refresh_rate *refresh_rate)
+{
+ dal_mode_query_reset_cofunc_view_solution_it(mq);
+
+ while (dal_mode_query_select_next_refresh_rate(mq))
+ if (dal_refresh_rate_is_equal(
+ get_current_refresh_rate(mq),
+ refresh_rate))
+ return true;
+
+ return false;
+}
+
+bool dal_mode_query_select_refresh_rate_ex(
+ struct mode_query *mq,
+ uint32_t refresh_rate,
+ bool interlaced)
+{
+ uint32_t field_rate = interlaced ? refresh_rate * 2 : refresh_rate;
+
+ dal_mode_query_reset_cofunc_view_solution_it(mq);
+
+ while (dal_mode_query_select_next_refresh_rate(mq)) {
+ const struct refresh_rate *refresh_rate =
+ get_current_refresh_rate(mq);
+
+ if (refresh_rate->field_rate == field_rate &&
+ refresh_rate->INTERLACED == interlaced)
+ return true;
+ }
+
+ return false;
+}
+
+/*
+void dal_mode_query_destroy(struct mode_query *mq);
+*/
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/mode_query.h b/drivers/gpu/drm/amd/dal/mode_manager/mode_query.h
new file mode 100644
index 000000000000..58e1733fccef
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/mode_query.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DAL_MODE_QUERY_H__
+#define __DAL_MODE_QUERY_H__
+
+#include "include/mode_query_interface.h"
+#include "include/mode_manager_types.h"
+#include "mode_query_set.h"
+#include "cofunctional_mode_validator.h"
+#include "solution.h"
+
+enum {
+ INVALID_VIEW_SOLUTION_INDEX = -1,
+};
+
+struct valid_iterators {
+ bool RENDER_MODE:1;
+ bool COFUNC_VIEW_SOLUTION:1;
+ bool COFUNC_SCALING_SUPPORT:1;
+ bool COFUNC_3D_VIEW:1;
+};
+
+union solution_filter {
+ struct bits {
+ uint32_t NO_CUSTOM_3D_MODES:1;
+ } bits;
+ uint32_t raw;
+};
+
+struct mode_query_funcs {
+ bool (*select_next_render_mode)(struct mode_query *mq);
+ bool (*select_next_scaling)(struct mode_query *mq);
+ bool (*select_next_refresh_rate)(struct mode_query *mq);
+ bool (*build_cofunc_view_solution_set)(struct mode_query *mq);
+ void (*destroy)(struct mode_query *mq);
+};
+
+struct mode_query {
+ const struct mode_query_funcs *funcs;
+ struct topology topology;
+ struct mode_query_set *query_set;
+ struct render_mode cur_render_mode;
+ uint32_t cur_path_idx_for_cofunc_rf;
+ bool is_valid;
+ union adapter_view_importance enum_adapter_view_match;
+ enum display_view_importance enum_display_view_level;
+ enum solution_importance enum_solution_importance;
+ union solution_filter solution_filter;
+
+ uint32_t cur_view_idx;
+ struct stereo_3d_view cur_3d_views[MAX_COFUNC_PATH];
+ enum view_3d_format cur_view_3d_format;
+ struct stereo_3d_view cur_stereo_3d_view;
+
+ uint32_t cur_view_solutions_idxs[MAX_COFUNC_PATH];
+ struct view_solution cur_view_solutions[MAX_COFUNC_PATH];
+ uint32_t cur_solution_idxs[MAX_COFUNC_PATH];
+
+ const struct solution *cur_solutions[MAX_COFUNC_PATH];
+ struct refresh_rate cur_refresh_rates[MAX_COFUNC_PATH];
+ const enum scaling_transformation *cofunc_scl[MAX_COFUNC_PATH];
+ uint32_t supported_scl_for_3d_mode;
+ struct cofunctional_mode_validator validator;
+ struct valid_iterators valid_iterators;
+};
+
+struct mode_query_init_data {
+ struct mode_query_set *query_set;
+ const struct ds_dispatch *ds_dispatch;
+ struct dal_context *ctx;
+};
+
+static inline struct view_solution get_solution_on_path_by_index(
+ struct mode_query *mq,
+ uint32_t path,
+ uint32_t index)
+{
+ const struct display_view_solution_container *dvsc =
+ mode_query_set_get_solution_container_on_path(
+ mq->query_set,
+ path);
+ return dal_dvsc_get_view_solution_at_index(
+ dvsc,
+ index);
+}
+
+bool dal_mode_query_construct(
+ struct mode_query *mq,
+ struct mode_query_init_data *mq_init_data);
+
+void dal_mode_query_destruct(struct mode_query *mq);
+
+bool dal_mode_query_base_select_next_refresh_rate(struct mode_query *mq);
+
+bool dal_mode_query_base_select_next_render_mode(struct mode_query *mq);
+
+void dal_mode_query_reset_cofunc_view_solution_it(struct mode_query *mq);
+
+bool dal_mode_query_select_min_resources_for_autoselect(struct mode_query *mq);
+
+void dal_mode_query_update_validator_entry(
+ struct mode_query *mq,
+ struct cofunctional_mode_validator *validator,
+ uint32_t validator_index, uint32_t mode_query_index);
+
+#endif /* __DAL_MODE_QUERY_H__ */
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/mode_query_allow_pan.c b/drivers/gpu/drm/amd/dal/mode_manager/mode_query_allow_pan.c
new file mode 100644
index 000000000000..30ee7cea090f
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/mode_query_allow_pan.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dal_services.h"
+#include "mode_query_allow_pan.h"
+
+struct mode_query_allow_pan {
+ struct mode_query base;
+ uint32_t panning_view_solution_indicies[MAX_COFUNC_PATH];
+};
+
+static bool build_cofunc_view_solution_set(struct mode_query *mq)
+{
+ struct mode_query_allow_pan *mq_allow_pan =
+ container_of(mq, struct mode_query_allow_pan, base);
+ uint32_t i;
+
+ for (i = 0; i < mq->query_set->num_path; i++) {
+ struct view_solution vs =
+ get_solution_on_path_by_index(mq, i, mq->cur_view_idx);
+
+ if (view_solution_get_display_view_importance(&vs) <=
+ mq->enum_display_view_level)
+ return true;
+
+ if (view_solution_get_count(&vs) > 0) {
+ mq->cur_view_solutions_idxs[i] = mq->cur_view_idx;
+ mq->cur_view_solutions[i] = vs;
+ } else {
+ struct view_solution vs_pan;
+
+ if (mq_allow_pan->panning_view_solution_indicies[i]
+ == INVALID_VIEW_SOLUTION_INDEX){
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+ vs_pan = get_solution_on_path_by_index(
+ mq,
+ i,
+ mq_allow_pan->
+ panning_view_solution_indicies[i]);
+ ASSERT(view_solution_get_count(&vs_pan) > 0);
+ ASSERT(mq->enum_display_view_level >=
+ view_solution_get_display_view_importance(
+ &vs_pan));
+
+ mq->cur_view_solutions_idxs[i] =
+ mq_allow_pan->
+ panning_view_solution_indicies[i];
+ mq->cur_view_solutions[i] = vs_pan;
+ }
+ }
+ return is_view_important_enough(
+ mq->query_set,
+ mq->cur_view_idx,
+ mq->enum_adapter_view_match);
+}
+
+static bool pan_on_limited_build_cofunc_view_solution_set(struct mode_query *mq)
+{
+ uint32_t i;
+ bool is_supported_by_at_least1 = false;
+
+ for (i = 0; i < mq->query_set->num_path; i++) {
+ struct view_solution vs = get_solution_on_path_by_index(
+ mq,
+ i,
+ mq->cur_view_idx);
+
+ if (view_solution_get_count(&vs) != 0) {
+ is_supported_by_at_least1 = true;
+ break;
+ }
+ }
+
+ return is_supported_by_at_least1 && build_cofunc_view_solution_set(mq);
+}
+
+static const struct mode_query_funcs
+mode_query_pan_on_limited_funcs = {
+ .select_next_render_mode =
+ dal_mode_query_base_select_next_render_mode,
+ .select_next_scaling =
+ dal_mode_query_base_select_next_scaling,
+ .select_next_refresh_rate =
+ dal_mode_query_base_select_next_refresh_rate,
+ .build_cofunc_view_solution_set =
+ pan_on_limited_build_cofunc_view_solution_set,
+};
+
+static const struct mode_query_funcs mode_query_allow_pan_funcs = {
+ .select_next_render_mode =
+ dal_mode_query_base_select_next_render_mode,
+ .select_next_scaling =
+ dal_mode_query_base_select_next_scaling,
+ .select_next_refresh_rate =
+ dal_mode_query_base_select_next_refresh_rate,
+ .build_cofunc_view_solution_set = build_cofunc_view_solution_set
+};
+
+static const struct mode_query_funcs
+mode_query_allow_pan_no_view_restriction_funcs = {
+ .select_next_render_mode =
+ dal_mode_query_base_select_next_render_mode,
+ .select_next_scaling =
+ dal_mode_query_base_select_next_scaling,
+ .select_next_refresh_rate =
+ dal_mode_query_base_select_next_refresh_rate,
+ .build_cofunc_view_solution_set = build_cofunc_view_solution_set
+};
+
+static bool mode_query_allow_pan_construct(
+ struct mode_query_allow_pan *mq_allow_pan,
+ struct mode_query_init_data *mq_init_data)
+{
+ if (!dal_mode_query_construct(&mq_allow_pan->base, mq_init_data))
+ return false;
+ mq_allow_pan->base.funcs = &mode_query_allow_pan_funcs;
+ return true;
+}
+
+static bool mode_query_allow_pan_on_limited_construct(
+ struct mode_query_allow_pan *mq_allow_pan_no_view_restriction,
+ struct mode_query_init_data *mq_init_data)
+{
+ if (!mode_query_allow_pan_construct(
+ mq_allow_pan_no_view_restriction,
+ mq_init_data))
+ return false;
+ mq_allow_pan_no_view_restriction->base.funcs =
+ &mode_query_pan_on_limited_funcs;
+ return true;
+}
+
+static bool mode_query_allow_pan_no_view_restriction_construct(
+ struct mode_query_allow_pan *mq,
+ struct mode_query_init_data *mq_init_data)
+{
+ if (!mode_query_allow_pan_construct(
+ mq,
+ mq_init_data))
+ return false;
+
+ mq->base.enum_adapter_view_match.flags.OPTIONAL = 1;
+ mq->base.enum_display_view_level =
+ DISPLAY_VIEW_IMPORTANCE_NON_GUARANTEED;
+ mq->base.enum_solution_importance = SOLUTION_IMPORTANCE_UNSAFE;
+ mq->base.funcs =
+ &mode_query_allow_pan_no_view_restriction_funcs;
+ return true;
+}
+
+struct mode_query *dal_mode_query_allow_pan_create(
+ struct mode_query_init_data *mq_init_data)
+{
+ struct mode_query_allow_pan *mq_allow_pan =
+ dal_alloc(sizeof(struct mode_query_allow_pan));
+
+ if (mq_allow_pan == NULL)
+ return NULL;
+
+ if (mode_query_allow_pan_construct(
+ mq_allow_pan,
+ mq_init_data))
+ return &mq_allow_pan->base;
+
+ dal_free(mq_allow_pan);
+ return NULL;
+}
+
+struct mode_query *dal_mode_query_pan_on_limited_create(
+ struct mode_query_init_data *mq_init_data)
+{
+ struct mode_query_allow_pan *mq_allow_pan_on_limited =
+ dal_alloc(sizeof(struct mode_query_allow_pan));
+ if (mq_allow_pan_on_limited == NULL)
+ return NULL;
+
+ if (mode_query_allow_pan_on_limited_construct(
+ mq_allow_pan_on_limited, mq_init_data))
+ return &mq_allow_pan_on_limited->base;
+
+ dal_free(mq_allow_pan_on_limited);
+ return NULL;
+}
+
+struct mode_query *dal_mode_query_allow_pan_no_view_restriction_create(
+ struct mode_query_init_data *mq_init_data)
+{
+ struct mode_query_allow_pan *mq_allow_pan_no_view_restriction =
+ dal_alloc(sizeof(struct mode_query_allow_pan));
+ if (mq_allow_pan_no_view_restriction == NULL)
+ return NULL;
+
+ if (mode_query_allow_pan_no_view_restriction_construct(
+ mq_allow_pan_no_view_restriction, mq_init_data))
+ return &mq_allow_pan_no_view_restriction->base;
+
+ dal_free(mq_allow_pan_no_view_restriction);
+ return NULL;
+}
+
+void dal_mode_query_allow_pan_post_initialize(struct mode_query *mq)
+{
+ uint32_t i;
+ struct mode_query_allow_pan *mq_allow_pan = container_of(
+ mq,
+ struct mode_query_allow_pan,
+ base);
+ for (i = 0; i < mq->query_set->num_path; i++) {
+ uint32_t j;
+
+ mq_allow_pan->panning_view_solution_indicies[i] =
+ INVALID_VIEW_SOLUTION_INDEX;
+
+ for (j = dal_mode_query_set_get_view_count(mq->query_set);
+ j > 0;
+ j--) {
+ struct view_solution vs =
+ get_solution_on_path_by_index(
+ mq,
+ i,
+ j - 1);
+
+ if (view_solution_get_count(&vs) == 0)
+ continue;
+
+ if (view_solution_get_display_view_importance(&vs) <=
+ DISPLAY_VIEW_IMPORTANCE_GUARANTEED) {
+
+ mq_allow_pan->panning_view_solution_indicies[i]
+ = j - 1;
+ break;
+ }
+
+ if (mq_allow_pan->
+ panning_view_solution_indicies[i] ==
+ INVALID_VIEW_SOLUTION_INDEX &&
+ view_solution_get_display_view_importance(&vs)
+ <= mq->enum_display_view_level)
+
+ mq_allow_pan->
+ panning_view_solution_indicies[i] =
+ j - 1;
+ }
+
+ ASSERT(mq_allow_pan->panning_view_solution_indicies[i] !=
+ INVALID_VIEW_SOLUTION_INDEX);
+ }
+}
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/mode_query_allow_pan.h b/drivers/gpu/drm/amd/dal/mode_manager/mode_query_allow_pan.h
new file mode 100644
index 000000000000..7e88898d1423
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/mode_query_allow_pan.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DAL_MODE_QUERY_ALLOW_PAN_H__
+#define __DAL_MODE_QUERY_ALLOW_PAN_H__
+
+#include "mode_query.h"
+
+struct mode_query *dal_mode_query_allow_pan_create(
+ struct mode_query_init_data *mq_init_data);
+
+struct mode_query *dal_mode_query_pan_on_limited_create(
+ struct mode_query_init_data *mq_init_data);
+
+struct mode_query *dal_mode_query_allow_pan_no_view_restriction_create(
+ struct mode_query_init_data *mq_init_data);
+
+void dal_mode_query_allow_pan_post_initialize(struct mode_query *mq);
+
+#endif /* __DAL_MODE_QUERY_ALLOW_PAN_H__ */
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/mode_query_no_pan.c b/drivers/gpu/drm/amd/dal/mode_manager/mode_query_no_pan.c
new file mode 100644
index 000000000000..eea1bb9175f5
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/mode_query_no_pan.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dal_services.h"
+
+#include "mode_query_no_pan.h"
+
+bool dal_mode_query_no_pan_build_cofunc_view_solution_set(struct mode_query *mq)
+{
+ bool is_display_view = false;
+ bool is_view_supported = true;
+ uint32_t i;
+
+ for (i = 0; i < mq->query_set->num_path; i++) {
+ struct view_solution vs = get_solution_on_path_by_index(
+ mq,
+ i,
+ mq->cur_view_idx);
+
+ if (view_solution_get_count(&vs) == 0) {
+ is_view_supported = false;
+ break;
+ }
+
+ mq->cur_view_solutions_idxs[i] = mq->cur_view_idx;
+ mq->cur_view_solutions[i] = vs;
+
+ if (view_solution_get_display_view_importance(&vs) <=
+ mq->enum_display_view_level)
+ is_display_view = true;
+ }
+
+ if (is_view_supported &&
+ (is_display_view ||
+ is_view_important_enough(
+ mq->query_set,
+ mq->cur_view_idx,
+ mq->enum_adapter_view_match)))
+ return true;
+
+ return false;
+}
+
+static void destroy(struct mode_query *mq)
+{
+ dal_mode_query_destruct(mq);
+}
+
+static const struct mode_query_funcs mode_query_no_pan_funcs = {
+ .select_next_render_mode =
+ dal_mode_query_base_select_next_render_mode,
+ .select_next_scaling =
+ dal_mode_query_base_select_next_scaling,
+ .select_next_refresh_rate =
+ dal_mode_query_base_select_next_refresh_rate,
+ .build_cofunc_view_solution_set =
+ dal_mode_query_no_pan_build_cofunc_view_solution_set,
+ .destroy = destroy
+};
+
+static bool mode_query_no_pan_construct(
+ struct mode_query *mq_no_pan,
+ struct mode_query_init_data *mq_init_data)
+{
+ if (!dal_mode_query_construct(mq_no_pan, mq_init_data))
+ return false;
+ mq_no_pan->funcs = &mode_query_no_pan_funcs;
+ return true;
+}
+
+static bool are_all_refresh_rates_equal_and_preferred(struct mode_query *mq)
+{
+ uint32_t i;
+
+ for (i = 0; i < mq->query_set->num_path; i++) {
+ ASSERT(mq->cur_solutions[i] != NULL);
+ if (mq->cur_solutions[i]->importance
+ > SOLUTION_IMPORTANCE_PREFERRED)
+ return false;
+
+ if (i > 0 && !dal_refresh_rate_is_equal(
+ &mq->cur_refresh_rates[i],
+ &mq->cur_refresh_rates[i - 1]))
+ return false;
+ }
+
+ return true;
+}
+
+static bool select_fallback_refresh_rate(
+ struct mode_query *mq)
+{
+ struct refresh_rate rf_60_hz = {
+ .field_rate = 60,
+ .INTERLACED = false};
+
+ dal_mode_query_reset_cofunc_view_solution_it(mq);
+
+ while (dal_mode_query_base_select_next_refresh_rate(mq))
+ if (!dal_refresh_rate_less_than(
+ dal_mode_query_get_current_refresh_rate(mq),
+ &rf_60_hz))
+ return mq->is_valid;
+
+
+ dal_mode_query_reset_cofunc_view_solution_it(mq);
+
+ while (dal_mode_query_base_select_next_refresh_rate(mq))
+ if (dal_refresh_rate_less_than(
+ dal_mode_query_get_current_refresh_rate(mq),
+ &rf_60_hz))
+ return mq->is_valid;
+
+ return false;
+}
+
+static bool mode_query_wide_top_select_next_refresh_rate(
+ struct mode_query *mq)
+{
+ bool new_view_solution = !mq->valid_iterators.COFUNC_VIEW_SOLUTION;
+
+ while (dal_mode_query_base_select_next_refresh_rate(mq))
+ if (are_all_refresh_rates_equal_and_preferred(mq))
+ break;
+
+ if (!mq->is_valid && new_view_solution)
+ mq->is_valid = select_fallback_refresh_rate(mq);
+
+ return mq->is_valid;
+}
+
+static const struct mode_query_funcs mode_query_wide_topology_funcs = {
+ .select_next_render_mode =
+ dal_mode_query_base_select_next_render_mode,
+ .select_next_scaling =
+ dal_mode_query_base_select_next_scaling,
+ .select_next_refresh_rate =
+ mode_query_wide_top_select_next_refresh_rate,
+ .build_cofunc_view_solution_set =
+ dal_mode_query_no_pan_build_cofunc_view_solution_set,
+ .destroy = destroy
+};
+
+static bool mode_query_wide_topology_construct(
+ struct mode_query *mq,
+ struct mode_query_init_data *mq_init_data)
+{
+ if (!dal_mode_query_construct(mq, mq_init_data))
+ return false;
+ mq->funcs = &mode_query_wide_topology_funcs;
+ return true;
+}
+
+static bool mode_query_3d_limited_candidates_construct(
+ struct mode_query *mq,
+ struct mode_query_init_data *mq_init_data)
+{
+ if (!dal_mode_query_construct(mq, mq_init_data))
+ return false;
+ mq->funcs = &mode_query_no_pan_funcs;
+
+ mq->supported_scl_for_3d_mode = 0;
+ mq->supported_scl_for_3d_mode |= SCALING_TRANSFORMATION_IDENTITY;
+ mq->solution_filter.bits.NO_CUSTOM_3D_MODES = true;
+
+ return true;
+}
+
+static bool mode_query_3d_limited_cand_wide_topology_construct(
+ struct mode_query *mq,
+ struct mode_query_init_data *mq_init_data)
+{
+ if (!mode_query_wide_topology_construct(mq, mq_init_data))
+ return false;
+ mq->funcs = &mode_query_wide_topology_funcs;
+
+ mq->supported_scl_for_3d_mode = 0;
+ mq->supported_scl_for_3d_mode |= SCALING_TRANSFORMATION_IDENTITY;
+ mq->solution_filter.bits.NO_CUSTOM_3D_MODES = true;
+
+ return true;
+}
+
+static bool mode_query_no_pan_no_display_view_restriction_construct(
+ struct mode_query *mq,
+ struct mode_query_init_data *mq_init_data)
+{
+ if (!dal_mode_query_construct(mq, mq_init_data))
+ return false;
+ mq->funcs = &mode_query_no_pan_funcs;
+
+ mq->enum_display_view_level = DISPLAY_VIEW_IMPORTANCE_NON_GUARANTEED;
+
+ return true;
+}
+
+struct mode_query *dal_mode_query_no_pan_create(
+ struct mode_query_init_data *mq_init_data)
+{
+ struct mode_query *mq_no_pan = dal_alloc(sizeof(struct mode_query));
+
+ if (mq_no_pan == NULL)
+ return NULL;
+
+ if (mode_query_no_pan_construct(
+ mq_no_pan,
+ mq_init_data))
+ return mq_no_pan;
+
+ dal_free(mq_no_pan);
+ return NULL;
+}
+
+struct mode_query *dal_mode_query_wide_topology_create(
+ struct mode_query_init_data *mq_init_data)
+{
+ struct mode_query *mq = dal_alloc(sizeof(struct mode_query));
+
+ if (mq == NULL)
+ return NULL;
+
+ if (mode_query_wide_topology_construct(
+ mq,
+ mq_init_data))
+ return mq;
+
+ dal_free(mq);
+ return NULL;
+}
+
+struct mode_query
+*dal_mode_query_no_pan_no_display_view_restriction_create(
+ struct mode_query_init_data *mq_init_data)
+{
+ struct mode_query *mq = dal_alloc(sizeof(struct mode_query));
+
+ if (mq == NULL)
+ return NULL;
+
+ if (mode_query_no_pan_no_display_view_restriction_construct(
+ mq,
+ mq_init_data))
+ return mq;
+
+ dal_free(mq);
+ return NULL;
+}
+
+struct mode_query *dal_mode_query_3d_limited_candidates_create(
+ struct mode_query_init_data *mq_init_data)
+{
+ struct mode_query *mq = dal_alloc(sizeof(struct mode_query));
+
+ if (mq == NULL)
+ return NULL;
+
+ if (mode_query_3d_limited_candidates_construct(
+ mq,
+ mq_init_data))
+ return mq;
+
+ dal_free(mq);
+ return NULL;
+}
+
+struct mode_query *dal_mode_query_3d_limited_cand_wide_topology_create(
+ struct mode_query_init_data *mq_init_data)
+{
+ struct mode_query *mq = dal_alloc(sizeof(struct mode_query));
+
+ if (mq == NULL)
+ return NULL;
+
+ if (mode_query_3d_limited_cand_wide_topology_construct(
+ mq,
+ mq_init_data))
+ return mq;
+
+ dal_free(mq);
+ return NULL;
+}
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/mode_query_no_pan.h b/drivers/gpu/drm/amd/dal/mode_manager/mode_query_no_pan.h
new file mode 100644
index 000000000000..61fb7a49f494
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/mode_query_no_pan.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DAL_MODE_QUERY_NO_PAN_H__
+#define __DAL_MODE_QUERY_NO_PAN_H__
+
+#include "mode_query.h"
+
+struct mode_query *dal_mode_query_no_pan_create(
+ struct mode_query_init_data *mq_init_data);
+
+struct mode_query *dal_mode_query_tiled_display_preferred_create(
+ struct mode_query_init_data *mq_init_data);
+
+struct mode_query *dal_mode_query_wide_topology_create(
+ struct mode_query_init_data *mq_init_data);
+
+struct mode_query
+*dal_mode_query_no_pan_no_display_view_restriction_create(
+ struct mode_query_init_data *mq_init_data);
+
+struct mode_query *dal_mode_query_3d_limited_cand_wide_topology_create(
+ struct mode_query_init_data *mq_init_data);
+
+struct mode_query *dal_mode_query_3d_limited_candidates_create(
+ struct mode_query_init_data *mq_init_data);
+
+bool dal_mode_query_no_pan_build_cofunc_view_solution_set
+(struct mode_query *mq);
+
+#endif /* __DAL_MODE_QUERY_NO_PAN_H__ */
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/mode_query_set.c b/drivers/gpu/drm/amd/dal/mode_manager/mode_query_set.c
new file mode 100644
index 000000000000..151a502b33db
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/mode_query_set.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#include "dal_services.h"
+#include "include/bit_set.h"
+#include "include/logger_interface.h"
+#include "mode_query_set.h"
+
+static bool construct(
+ struct mode_query_set *mqs,
+ struct mode_query_set_init_data *mqs_init_data)
+{
+ mqs->dal_ctx = mqs_init_data->ctx;
+ mqs->master_view_info_list = mqs_init_data->master_view_list;
+
+ dal_pixel_format_list_construct(
+ &mqs->pixel_format_list_iterator,
+ mqs_init_data->supported_pixel_format);
+
+ return true;
+}
+
+struct mode_query_set *dal_mode_query_set_create(
+ struct mode_query_set_init_data *mqs_init_data)
+{
+ struct mode_query_set *mqs = dal_alloc(sizeof(struct mode_query_set));
+
+ if (mqs == NULL)
+ return NULL;
+
+ if (construct(mqs, mqs_init_data))
+ return mqs;
+
+ dal_free(mqs);
+ return NULL;
+}
+
+static void destruct(struct mode_query_set *set)
+{
+}
+
+void dal_mode_query_set_destroy(struct mode_query_set **set)
+{
+ if (!set || !*set)
+ return;
+
+ destruct(*set);
+
+ dal_free(*set);
+ *set = NULL;
+}
+
+bool dal_mode_query_set_add_solution_container(
+ struct mode_query_set *mqs,
+ struct display_view_solution_container *container)
+{
+ uint32_t i;
+
+ if (container == NULL) {
+ dal_logger_write(mqs->dal_ctx->logger,
+ LOG_MAJOR_WARNING,
+ LOG_MINOR_MODE_ENUM_MASTER_VIEW_LIST,
+ " %s:%d: Solution Container is NULL!\n",
+ __func__, __LINE__);
+ return false;
+ }
+
+ if (mqs->num_path >= MAX_COFUNC_PATH) {
+ dal_logger_write(mqs->dal_ctx->logger,
+ LOG_MAJOR_WARNING,
+ LOG_MINOR_MODE_ENUM_MASTER_VIEW_LIST,
+ " %s:%d: num_path:%d exceeds maximum:%d !\n",
+ __func__, __LINE__, mqs->num_path, MAX_COFUNC_PATH);
+ return false;
+ }
+
+ if (!container->is_valid) {
+ dal_logger_write(mqs->dal_ctx->logger,
+ LOG_MAJOR_WARNING,
+ LOG_MINOR_MODE_ENUM_MASTER_VIEW_LIST,
+ " %s:%d: Solution Container not marked as valid!\n",
+ __func__, __LINE__);
+ return false;
+ }
+
+ for (i = 0; i < mqs->num_path; i++) {
+ if (mqs->solutions[i] == container) {
+ dal_logger_write(mqs->dal_ctx->logger,
+ LOG_MAJOR_WARNING,
+ LOG_MINOR_MODE_ENUM_MASTER_VIEW_LIST,
+ " %s:%d: Container ALREADY in query set!\n",
+ __func__, __LINE__);
+ return false;
+ }
+ }
+
+ mqs->solutions[mqs->num_path++] = container;
+ return true;
+}
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/mode_query_set.h b/drivers/gpu/drm/amd/dal/mode_manager/mode_query_set.h
new file mode 100644
index 000000000000..49f7e58912ce
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/mode_query_set.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DAL_MODE_QUERY_SET_H__
+#define __DAL_MODE_QUERY_SET_H__
+
+#include "include/flat_set.h"
+#include "include/mode_manager_types.h"
+#include "view_solution.h"
+#include "mode_query_set.h"
+#include "display_view_solution_container.h"
+
+struct mode_query_set {
+ struct dal_context *dal_ctx;
+ struct pixel_format_list pixel_format_list_iterator;
+ const struct view_info_list *master_view_info_list;
+ uint32_t num_path;
+
+ const struct display_view_solution_container
+ *solutions[MAX_COFUNC_PATH];
+};
+
+struct mode_query_set_init_data {
+ struct dal_context *ctx;
+ uint32_t supported_pixel_format;
+ struct view_info_list *master_view_list;
+};
+
+struct mode_query_set *dal_mode_query_set_create(
+ struct mode_query_set_init_data *mqs_init_data);
+
+void dal_mode_query_set_destroy(struct mode_query_set **set);
+
+bool dal_mode_query_set_add_solution_container(
+ struct mode_query_set *mqs,
+ struct display_view_solution_container *container);
+
+static inline const uint32_t dal_mode_query_set_get_pixel_format_count(
+ const struct mode_query_set *mode_query_set)
+{
+ return dal_pixel_format_list_get_count(
+ &mode_query_set->pixel_format_list_iterator);
+}
+
+static inline const uint32_t dal_mode_query_set_get_pixel_format(
+ const struct mode_query_set *mode_query_set)
+{
+ return dal_pixel_format_list_get_pixel_format(
+ &mode_query_set->pixel_format_list_iterator);
+}
+
+static inline const struct view *mode_query_set_get_view_at_index(
+ const struct mode_query_set *mqs,
+ uint32_t index)
+{
+ struct view_info *vw_inf = dal_flat_set_at_index(
+ &mqs->master_view_info_list->set,
+ index);
+
+ return &vw_inf->view;
+}
+
+static inline const struct display_view_solution_container
+ *mode_query_set_get_solution_container_on_path(
+ const struct mode_query_set *mqs,
+ uint32_t container_idx)
+{
+ return mqs->solutions[container_idx];
+}
+
+static inline uint32_t dal_mode_query_set_get_view_count(
+ const struct mode_query_set *mqs)
+{
+ return dal_view_info_list_get_count(mqs->master_view_info_list);
+}
+
+static inline bool is_view_important_enough(
+ struct mode_query_set *mqs,
+ uint32_t index,
+ union adapter_view_importance importance)
+{
+ union adapter_view_importance cur_importance =
+ dal_view_info_list_at_index(
+ mqs->master_view_info_list,
+ index)->importance;
+
+ if (mqs->num_path <= 2 &&
+ (cur_importance.flags.GUARANTEED ||
+ cur_importance.flags.GUARANTEED_16X9 ||
+ cur_importance.flags.GUARANTEED_16X10) &&
+ !cur_importance.flags.DEFAULT_VIEW)
+ return false;
+
+ return (cur_importance.value & importance.value) != 0;
+}
+
+#endif /* __DAL_MODE_QUERY_SET_H__ */
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/mode_query_tiled_display_preferred.c b/drivers/gpu/drm/amd/dal/mode_manager/mode_query_tiled_display_preferred.c
new file mode 100644
index 000000000000..c4dff3065b6b
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/mode_query_tiled_display_preferred.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dal_services.h"
+#include "mode_query_tiled_display_preferred.h"
+
+/*TODO to be implemented */
+static bool select_next_render_mode(struct mode_query *mq)
+{
+ return false;
+}
+
+static bool select_next_scaling(struct mode_query *mq)
+{
+ uint32_t i;
+ uint32_t path_num = dal_pms_get_path_mode_num(
+ dal_mode_query_get_current_path_mode_set(mq));
+ dal_mode_query_base_select_next_scaling(mq);
+
+ for (i = 0; i < path_num; i++)
+ if (*mq->cofunc_scl[i] != SCALING_TRANSFORMATION_IDENTITY)
+ return false;
+
+ return true;
+}
+
+/*TODO to be implemented */
+static bool select_next_refresh_rate(struct mode_query *mq)
+{
+ return false;
+}
+
+static void destroy(struct mode_query *mq)
+{
+ dal_mode_query_destruct(mq);
+}
+
+static const struct mode_query_funcs
+mode_query_tiled_display_preferred_funcs = {
+ .select_next_render_mode =
+ select_next_render_mode,
+ .select_next_scaling =
+ select_next_scaling,
+ .select_next_refresh_rate =
+ select_next_refresh_rate,
+ .build_cofunc_view_solution_set =
+ dal_mode_query_no_pan_build_cofunc_view_solution_set,
+ .destroy = destroy
+};
+
+static bool mode_query_tiled_display_preferred_construct(
+ struct mode_query *mq,
+ struct mode_query_init_data *mq_init_data)
+{
+ if (!dal_mode_query_construct(mq, mq_init_data))
+ return false;
+ mq->funcs = &mode_query_tiled_display_preferred_funcs;
+
+ return true;
+}
+
+struct mode_query *dal_mode_query_tiled_display_preferred_create(
+ struct mode_query_init_data *mq_init_data)
+{
+ struct mode_query *mq = dal_alloc(sizeof(struct mode_query));
+
+ if (mq == NULL)
+ return NULL;
+
+ if (mode_query_tiled_display_preferred_construct(
+ mq,
+ mq_init_data))
+ return mq;
+
+ dal_free(mq);
+ return NULL;
+}
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/mode_query_tiled_display_preferred.h b/drivers/gpu/drm/amd/dal/mode_manager/mode_query_tiled_display_preferred.h
new file mode 100644
index 000000000000..94dda4144a84
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/mode_query_tiled_display_preferred.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DAL_MODE_QUERY_TILED_DISPLAY_PREFERRED_H__
+#define __DAL_MODE_QUERY_TILED_DISPLAY_PREFERRED_H__
+
+#include "mode_query_no_pan.h"
+
+enum {
+ MAX_TILED_DISPLAY_PREFERRED_MODES = 3,
+};
+
+struct mode_query_tiled_display_preferred {
+ struct mode_query base;
+ uint32_t tiled_preferred_mode_count;
+ struct view render_modes_enumerated[MAX_TILED_DISPLAY_PREFERRED_MODES];
+};
+
+struct mode_query *dal_mode_query_tiled_display_preferred_create(
+ struct mode_query_init_data *mq_init_data);
+
+#endif /* __DAL_MODE_QUERY_TILED_DISPLAY_PREFERRED_H__ */
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/solution.c b/drivers/gpu/drm/amd/dal/mode_manager/solution.c
new file mode 100644
index 000000000000..f9eee7836295
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/solution.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dal_services.h"
+#include "solution.h"
+
+bool dal_solution_construct(struct solution *solution,
+ const struct mode_timing *mode_timing,
+ enum solution_importance importance)
+{
+ uint32_t i;
+
+ if (mode_timing == NULL)
+ return false;
+
+ solution->mode_timing = mode_timing;
+ solution->importance = importance;
+
+ for (i = 0; i < NUM_PIXEL_FORMATS; i++) {
+ solution->scl_support[i] = 0;
+ solution->scl_support_guaranteed[i] = 0;
+ }
+
+ switch (mode_timing->mode_info.timing_source) {
+ case TIMING_SOURCE_CUSTOM:
+ case TIMING_SOURCE_CUSTOM_BASE:
+ case TIMING_SOURCE_USER_FORCED:
+ solution->is_custom_mode = true;
+ break;
+ default:
+ solution->is_custom_mode = false;
+ break;
+ };
+
+ /* Setup solution importance (unless was strictly defined by caller)*/
+ if (importance == SOLUTION_IMPORTANCE_DEFAULT) {
+ switch (solution->mode_timing->mode_info.timing_source) {
+ case TIMING_SOURCE_RANGELIMIT:
+ case TIMING_SOURCE_OS_FORCED:
+ case TIMING_SOURCE_DALINTERFACE_IMPLICIT:
+ solution->importance = SOLUTION_IMPORTANCE_UNSAFE;
+ break;
+ default:
+ solution->importance = SOLUTION_IMPORTANCE_SAFE;
+ break;
+ }
+ }
+ return true;
+}
+
+void dal_solution_set_support_matrix(
+ struct solution *solution,
+ enum pixel_format pf,
+ enum scaling_transformation st,
+ bool support,
+ bool guaranteed)
+{
+ uint32_t i = get_support_index_for_pixel_fmt(pf);
+
+ if (support)
+ solution->scl_support[i] |= st;
+ if (guaranteed)
+ solution->scl_support_guaranteed[i] |= st;
+}
+
+static bool solution_less_then(const void *p1, const void *p2)
+{
+ const struct solution *s1 = p1;
+ const struct solution *s2 = p2;
+
+ if (s1->mode_timing->mode_info.flags.INTERLACE <
+ s2->mode_timing->mode_info.flags.INTERLACE)
+ return true;
+ if (s1->mode_timing->mode_info.flags.INTERLACE >
+ s2->mode_timing->mode_info.flags.INTERLACE)
+ return false;
+
+ if (s1->mode_timing->mode_info.field_rate >
+ s2->mode_timing->mode_info.field_rate)
+ return true;
+ if (s1->mode_timing->mode_info.field_rate <
+ s2->mode_timing->mode_info.field_rate)
+ return false;
+
+ if (s1->mode_timing->mode_info.flags.VIDEO_OPTIMIZED_RATE <
+ s2->mode_timing->mode_info.flags.VIDEO_OPTIMIZED_RATE)
+ return true;
+ if (s1->mode_timing->mode_info.flags.VIDEO_OPTIMIZED_RATE >
+ s2->mode_timing->mode_info.flags.VIDEO_OPTIMIZED_RATE)
+ return false;
+
+ if (s1->mode_timing->crtc_timing.timing_3d_format <
+ s2->mode_timing->crtc_timing.timing_3d_format)
+ return true;
+ if (s1->mode_timing->crtc_timing.timing_3d_format >
+ s2->mode_timing->crtc_timing.timing_3d_format)
+ return false;
+
+ return s1->mode_timing->mode_info.timing_source <
+ s2->mode_timing->mode_info.timing_source;
+}
+
+#define SOLUTION_SET_INITIAL_CAPACITY 100
+
+bool dal_solution_set_construct(struct solution_set *ss)
+{
+ struct flat_set_init_data data;
+
+ data.capacity = SOLUTION_SET_INITIAL_CAPACITY;
+ data.struct_size = sizeof(struct solution);
+ data.funcs.less_than = solution_less_then;
+ return dal_flat_set_construct(&ss->set, &data);
+}
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/solution.h b/drivers/gpu/drm/amd/dal/mode_manager/solution.h
new file mode 100644
index 000000000000..c8b1fb5d5145
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/solution.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DAL_SOLUTION_H__
+#define __DAL_SOLUTION_H__
+
+#include "include/timing_service_types.h"
+#include "include/set_mode_interface.h"
+#include "include/mode_manager_types.h"
+#include "include/flat_set.h"
+
+enum display_view_importance {
+ DISPLAY_VIEW_IMPORTANCE_BESTVIEW_OVERRIDE = 1,
+ /* the most importance, coming from bestview*/
+ /* regular ModeMgr View importance*/
+ DISPLAY_VIEW_IMPORTANCE_GUARANTEED,
+ /* always enumerated */
+ DISPLAY_VIEW_IMPORTANCE_OPTIONAL,
+ /* enumerate if number of display in topology <= 2*/
+ DISPLAY_VIEW_IMPORTANCE_RESTRICTED,
+ /* enumerate if topology is single display*/
+ DISPLAY_VIEW_IMPORTANCE_NON_GUARANTEED,
+ /* enumerate by other display (not enumerated by this display)*/
+};
+
+struct solution_set {
+ struct flat_set set;
+};
+
+bool dal_solution_construct(
+ struct solution *solution,
+ const struct mode_timing *mode_timing,
+ enum solution_importance importance);
+
+static inline enum solution_importance dal_solution_get_importance(
+ const struct solution *solution)
+{
+ return solution->importance;
+}
+
+static inline bool dal_solution_is_empty(struct solution *solution)
+{
+ uint32_t i;
+
+ for (i = 0; i < NUM_PIXEL_FORMATS; i++)
+ if (solution->scl_support[i])
+ return false;
+ return true;
+}
+
+static inline uint32_t get_support_index_for_pixel_fmt(
+ enum pixel_format pf)
+{
+ switch (pf) {
+ case PIXEL_FORMAT_INDEX8:
+ return 0;
+ case PIXEL_FORMAT_RGB565:
+ return 1;
+ case PIXEL_FORMAT_ARGB8888:
+ return 2;
+ case PIXEL_FORMAT_ARGB2101010:
+ return 3;
+ case PIXEL_FORMAT_ARGB2101010_XRBIAS:
+ return 4;
+ case PIXEL_FORMAT_FP16:
+ return 5;
+ case PIXEL_FORMAT_420BPP12:
+ return 6;
+ case PIXEL_FORMAT_422BPP16:
+ return 7;
+ case PIXEL_FORMAT_444BPP16:
+ return 8;
+ case PIXEL_FORMAT_444BPP32:
+ return 9;
+ default:
+ BREAK_TO_DEBUGGER();
+ return 2;
+ }
+}
+
+static inline bool dal_solution_is_supported(
+ const struct solution *solution,
+ enum pixel_format pf,
+ enum scaling_transformation st)
+{
+ uint32_t i = get_support_index_for_pixel_fmt(pf);
+
+ if (i >= NUM_PIXEL_FORMATS) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+ return solution->scl_support[i] & st;
+}
+
+static inline bool dal_solution_is_guaranteed(
+ const struct solution *sol,
+ enum pixel_format pf,
+ enum scaling_transformation st)
+{
+ uint32_t i = get_support_index_for_pixel_fmt(pf);
+
+ return (sol->scl_support_guaranteed[i] & st) != 0;
+}
+
+bool dal_solution_set_construct(struct solution_set *ss);
+
+static inline void solution_set_destruct(struct solution_set *ss)
+{
+ dal_flat_set_destruct(&ss->set);
+}
+
+void dal_solution_set_support_matrix(
+ struct solution *solution,
+ enum pixel_format pf,
+ enum scaling_transformation st,
+ bool support,
+ bool guaranteed);
+
+static inline bool solution_set_insert(
+ struct solution_set *sol_set,
+ struct solution *solution)
+{
+ return dal_flat_set_insert(&sol_set->set, solution);
+}
+
+static inline uint32_t solution_set_get_count(
+ struct solution_set *sol_set)
+{
+ return dal_flat_set_get_count(&sol_set->set);
+}
+
+static inline void solution_update_importance(
+ struct solution *solution,
+ enum solution_importance si)
+{
+ solution->importance = si;
+}
+
+static inline struct solution *solution_set_at_index(
+ struct solution_set *sol_set,
+ uint32_t index)
+{
+ return dal_flat_set_at_index(&sol_set->set, index);
+}
+
+static inline void solution_set_clear(
+ struct solution_set *sol_set)
+{
+ return dal_flat_set_clear(&sol_set->set);
+}
+
+struct solution_key {
+ uint32_t start_index;
+ uint32_t count;
+ enum display_view_importance importance;
+};
+
+#endif /*__DAL_SOLUTION_H__*/
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/view_solution.c b/drivers/gpu/drm/amd/dal/mode_manager/view_solution.c
new file mode 100644
index 000000000000..1a1fec2719f5
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/view_solution.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dal_services.h"
+#include "include/vector.h"
+#include "view_solution.h"
+
+static bool view_less_then(const struct view *lhs, const struct view *rhs)
+{
+ if (lhs->width < rhs->width)
+ return true;
+ if (rhs->width < lhs->width)
+ return false;
+
+ if (lhs->height < rhs->height)
+ return true;
+
+ return false;
+}
+
+static bool view_info_list_less_then(const void *lhs, const void *rhs)
+{
+ const struct view_info *lvi = lhs;
+ const struct view_info *rvi = rhs;
+
+ return view_less_then(&lvi->view, &rvi->view);
+}
+
+#define VIEW_INFO_LIST_INITIAL_CAPACITY 10
+
+bool dal_view_info_list_construct(
+ struct view_info_list *vil,
+ struct view min_view_override,
+ struct view max_view_override,
+ bool force_min_max_res)
+{
+ struct flat_set_init_data data;
+
+ data.capacity = VIEW_INFO_LIST_INITIAL_CAPACITY;
+ data.struct_size = sizeof(struct view_info);
+ data.funcs.less_than = view_info_list_less_then;
+
+ if (!dal_flat_set_construct(&vil->set, &data))
+ return false;
+
+ vil->force_min_max_resolution = force_min_max_res;
+ vil->min_view_override = min_view_override;
+ vil->max_view_override = max_view_override;
+
+ return true;
+}
+
+void dal_view_info_list_destruct(
+ struct view_info_list *vil)
+{
+ dal_flat_set_destruct(&vil->set);
+}
+
+bool dal_view_info_list_insert(
+ struct view_info_list *vil,
+ const struct view_info *vi)
+{
+ return dal_flat_set_insert(&vil->set, vi);
+}
+bool dal_view_info_list_find(
+ struct view_info_list *vil,
+ struct view_info *vi,
+ uint32_t *index)
+{
+ return dal_flat_set_search(&vil->set, vi, index);
+}
+
+uint32_t dal_view_info_list_get_count(
+ const struct view_info_list *view_info_list)
+{
+ return dal_flat_set_get_count(&view_info_list->set);
+}
+
+struct view_info *dal_view_info_list_at_index(
+ const struct view_info_list *view_info_list,
+ uint32_t index)
+{
+ return dal_flat_set_at_index(&view_info_list->set, index);
+}
+
+uint32_t dal_view_info_list_capacity(
+ const struct view_info_list *view_info_list)
+{
+ return dal_flat_set_capacity(&view_info_list->set);
+}
+
+bool dal_view_info_list_reserve(
+ struct view_info_list *view_info_list,
+ uint32_t capacity)
+{
+ return dal_flat_set_reserve(&view_info_list->set, capacity);
+}
diff --git a/drivers/gpu/drm/amd/dal/mode_manager/view_solution.h b/drivers/gpu/drm/amd/dal/mode_manager/view_solution.h
new file mode 100644
index 000000000000..79ca8fe412eb
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/mode_manager/view_solution.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2012-15 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DAL_VIEW_SOLUTION_H__
+#define __DAL_VIEW_SOLUTION_H__
+
+#include "include/vector.h"
+#include "include/set_mode_interface.h"
+#include "best_view.h"
+
+union adapter_view_importance {
+ uint32_t value;
+ struct {
+ uint32_t GUARANTEED:1; /* enumerated in all cases */
+ /* enumerated if any display in topology is wide aspect display
+ */
+ uint32_t GUARANTEED_16X9:1;
+ /* enumerated if any display in topology is wide aspect display
+ */
+ uint32_t GUARANTEED_16X10:1;
+ /* enumerated if number of display in topology <= 2 */
+ uint32_t OPTIONAL:1;
+ /* indicate that this view come from default mode list */
+ uint32_t DEFAULT_VIEW:1;
+ uint32_t PREFERRED_VIEW:1; /* view is preferred */
+
+ } flags;
+};
+
+enum {
+ ADAPTER_VIEW_IMPORTANCE_GUARANTEED = 0x1,
+ ADAPTER_VIEW_IMPORTANCE_GUARANTEED_16x9 = 0x2,
+ ADAPTER_VIEW_IMPORTANCE_GUARANTEED_16x10 = 0x4,
+};
+
+struct view_info {
+ struct view view;
+ union adapter_view_importance importance;
+};
+
+struct view_info_list {
+ bool force_min_max_resolution;
+ struct view min_view_override;
+ struct view max_view_override;
+ struct flat_set set;
+};
+
+bool dal_view_info_list_construct(
+ struct view_info_list *vil,
+ struct view min_view_override,
+ struct view max_view_override,
+ bool force_min_max_res);
+
+void dal_view_info_list_destruct(
+ struct view_info_list *vil);
+
+bool dal_view_info_list_insert(
+ struct view_info_list *vil,
+ const struct view_info *vi);
+
+bool dal_view_info_list_find(
+ struct view_info_list *vil,
+ struct view_info *vi,
+ uint32_t *index);
+
+enum mode_aspect_ratio {
+ MODE_ASPECT_RATIO_UNKNOWN,
+ MODE_ASPECT_RATIO_4X3,
+ MODE_ASPECT_RATIO_5X4,
+ MODE_ASPECT_RATIO_16X9,
+ MODE_ASPECT_RATIO_16X10
+};
+
+struct view_solution {
+ const struct view *view;
+ const struct vector *store;
+ const struct solution_key *key;
+};
+
+uint32_t dal_view_info_list_get_count(
+ const struct view_info_list *view_info_list);
+
+struct view_info *dal_view_info_list_at_index(
+ const struct view_info_list *view_info_list,
+ uint32_t index);
+
+uint32_t dal_view_info_list_capacity(
+ const struct view_info_list *view_info_list);
+
+bool dal_view_info_list_reserve(
+ struct view_info_list *view_info_list,
+ uint32_t capacity);
+
+/* identify if the importance of the view
+ * and the view should be enumerated or not */
+static inline enum display_view_importance
+ view_solution_get_display_view_importance(
+ const struct view_solution *vw_sol)
+{
+ return vw_sol->key->importance;
+}
+
+static inline void view_solution_construct(
+ struct view_solution *vw_sol,
+ const struct view *vw,
+ const struct vector *store,
+ const struct solution_key *disp_info)
+{
+ vw_sol->view = vw;
+ vw_sol->store = store;
+ vw_sol->key = disp_info;
+}
+
+static inline uint32_t view_solution_get_count(
+ const struct view_solution *vw_sol)
+{
+ return vw_sol->key->count;
+}
+
+static inline const struct solution
+ *view_solution_get_solution_at_index(
+ const struct view_solution *vw_sol,
+ uint32_t index)
+{
+ return dal_vector_at_index(
+ vw_sol->store,
+ vw_sol->key->start_index + index);
+}
+
+#define SOLUTION_CONTAINER_LIST_INITIAL_CAPACITY 10
+
+#endif /* __DAL_VIEW_SOLUTION_H__ */