summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarry Wentland <harry.wentland@amd.com>2015-07-31 22:03:33 -0400
committerAlex Deucher <alexander.deucher@amd.com>2015-09-21 17:45:16 -0400
commit7a366fa8360a48b1d22e40bf170c21e9fb1be2ee (patch)
tree9df11ed0c7144356e1292bb53b7369333848556d
parent622b586fbab151ccaaddf3ac9d321ff5bfbbc7e8 (diff)
amd/dal: Display Service
The display service maintains display state, implements driver feature policy, builds parameters for HW programming, and call HWSS to program HW. SW Layer /===============================================================\ | Display Timing Mode Asic | | Service Service Manager Capability | | | | Display Topology Display Link Adapter | | Path Manager 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/Makefile5
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/Makefile14
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/adjustment_api.c292
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/adjustment_api.h64
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/adjustment_container.c591
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/adjustment_container.h207
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/adjustment_types_internal.h198
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/backlight_adj_group.c500
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/backlight_adj_group.h97
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/color_temperature.c212
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/color_temperature.h56
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/display_service.c631
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/display_service.h30
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/ds_calculation.c288
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/ds_calculation.h48
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/ds_dispatch.h137
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/ds_dispatch_adjustment.c1128
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/ds_dispatch_info_frame.c957
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/ds_dispatch_mode_setting.c2609
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/ds_dispatch_planes.c133
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/ds_overlay.c202
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/ds_translation.c560
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/ds_translation.h99
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/gamma_lut.c391
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/gamma_lut.h89
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/gamut_space.c1140
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/gamut_space.h270
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/grph_colors_group.c1326
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/grph_colors_group.h124
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/path_mode_set.c220
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/path_mode_set_with_data.c308
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/path_mode_set_with_data.h134
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/scaler_adj_group.c944
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/scaler_adj_group.h57
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/set_mode_params.c822
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/single_adj_group.c447
-rw-r--r--drivers/gpu/drm/amd/dal/display_service/single_adj_group.h75
-rw-r--r--drivers/gpu/drm/amd/dal/include/adjustment_interface.h230
-rw-r--r--drivers/gpu/drm/amd/dal/include/display_service_interface.h165
-rw-r--r--drivers/gpu/drm/amd/dal/include/overlay_interface.h137
-rw-r--r--drivers/gpu/drm/amd/dal/include/overlay_types.h164
41 files changed, 16099 insertions, 2 deletions
diff --git a/drivers/gpu/drm/amd/dal/Makefile b/drivers/gpu/drm/amd/dal/Makefile
index b697398d7e4f..b95ba1e51f55 100644
--- a/drivers/gpu/drm/amd/dal/Makefile
+++ b/drivers/gpu/drm/amd/dal/Makefile
@@ -8,8 +8,9 @@ AMDDALPATH = $(RELATIVE_AMD_DAL_PATH)
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 mode_manager timing_service topology
+ controller dcs display_service display_path encoder gpio gpu \
+ hw_sequencer i2caux irq link_service mode_manager timing_service \
+ topology
AMD_DAL = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DAL_PATH)/,$(DAL_LIBS)))
diff --git a/drivers/gpu/drm/amd/dal/display_service/Makefile b/drivers/gpu/drm/amd/dal/display_service/Makefile
new file mode 100644
index 000000000000..8482bdf5b8ca
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for the 'display_service' sub-component of DAL.
+# It provides the control and status of availible display services.
+
+DS = display_service.o path_mode_set.o set_mode_params.o \
+ ds_dispatch_adjustment.o ds_overlay.o ds_calculation.o grph_colors_group.o \
+ adjustment_container.o ds_dispatch_info_frame.o \
+ ds_dispatch_mode_setting.o ds_dispatch_planes.o ds_translation.o adjustment_api.o \
+ scaler_adj_group.o backlight_adj_group.o single_adj_group.o \
+ gamut_space.o color_temperature.o path_mode_set_with_data.o gamma_lut.o
+
+AMD_DAL_DS = $(addprefix $(AMDDALPATH)/display_service/,$(DS))
+
+AMD_DAL_FILES += $(AMD_DAL_DS)
diff --git a/drivers/gpu/drm/amd/dal/display_service/adjustment_api.c b/drivers/gpu/drm/amd/dal/display_service/adjustment_api.c
new file mode 100644
index 000000000000..4ceab23383a4
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/adjustment_api.c
@@ -0,0 +1,292 @@
+/*
+ * 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/adjustment_interface.h"
+#include "include/display_path_interface.h"
+#include "display_service/adjustment_types_internal.h"
+
+#include "adjustment_api.h"
+
+static const struct range_adjustment_api default_adj_range_dfp_table[] = {
+ { ADJ_ID_SATURATION, 100, 0, 200, 1, {0} },
+ { ADJ_ID_UNDERSCAN, 0, 0, 15, 1, {0} },
+ { ADJ_ID_BIT_DEPTH_REDUCTION, 1, 0, 23, 1, {0} },
+ { ADJ_ID_BACKLIGHT, 255, 0, 255, 1, {0} },
+ { ADJ_ID_BRIGHTNESS, 0, -100, 100, 1, {0} },
+ { ADJ_ID_CONTRAST, 100, 0, 200, 1, {0} },
+ { ADJ_ID_HUE, 0, -30, 30, 1, {0} },
+ { ADJ_ID_TEMPERATURE, 6500, 4000, 10000, 100, {0} },
+ { ADJ_ID_TEMPERATURE_SOURCE, 2, 1, 2, 1, {0} },
+ { ADJ_ID_NOMINAL_RANGE_RGB_LIMITED, 0, 0, 1, 1, {0} },
+};
+
+static const struct range_adjustment_api default_adj_range_crt_table[] = {
+ { ADJ_ID_SATURATION, 100, 0, 200, 1, {0} },
+ { ADJ_ID_BRIGHTNESS, 0, -100, 100, 1, {0} },
+ { ADJ_ID_CONTRAST, 100, 0, 200, 1, {0} },
+ { ADJ_ID_HUE, 0, -30, 30, 1, {0} },
+ { ADJ_ID_TEMPERATURE, 6500, 4000, 10000, 100, {0} },
+ { ADJ_ID_TEMPERATURE_SOURCE, 2, 1, 2, 1, {0} },
+ { ADJ_ID_NOMINAL_RANGE_RGB_LIMITED, 0, 0, 1, 1, {0} },
+ { ADJ_ID_BACKLIGHT, 255, 0, 255, 1, {0} },
+};
+
+static const struct range_adjustment_api default_adj_range_lcd_table[] = {
+ { ADJ_ID_SATURATION, 100, 0, 200, 1, {0} },
+ { ADJ_ID_UNDERSCAN, 0, 0, 10, 1, {0} },
+ { ADJ_ID_BIT_DEPTH_REDUCTION, 1, 0, 23, 1, {0} },
+ { ADJ_ID_BACKLIGHT, 255, 0, 255, 1, {0} },
+ { ADJ_ID_BRIGHTNESS, 0, -100, 100, 1, {0} },
+ { ADJ_ID_CONTRAST, 100, 0, 200, 1, {0} },
+ { ADJ_ID_HUE, 0, -30, 30, 1, {0} },
+ { ADJ_ID_TEMPERATURE, 6500, 4000, 10000, 100, {0} },
+ { ADJ_ID_TEMPERATURE_SOURCE, 2, 1, 2, 1, {0} },
+ { ADJ_ID_NOMINAL_RANGE_RGB_LIMITED, 0, 0, 1, 1, {0} },
+
+
+
+};
+
+static void destruct(struct adjustment_api *adj_api)
+{
+ if (adj_api->range_table) {
+ dal_free(adj_api->range_table);
+ adj_api->range_table = NULL;
+ }
+}
+
+static bool build_default_adj_table(struct adjustment_api *adj_api)
+{
+ uint32_t i;
+ uint32_t range_alloc_size = 0;
+ const struct range_adjustment_api *tmp_range_table = NULL;
+
+ switch (adj_api->adj_category) {
+ case CAT_CRT:
+ adj_api->range_table_size = sizeof(default_adj_range_crt_table)
+ / sizeof(default_adj_range_crt_table[0]);
+ tmp_range_table = default_adj_range_crt_table;
+ break;
+ case CAT_DFP:
+ adj_api->range_table_size = sizeof(default_adj_range_dfp_table)
+ / sizeof(default_adj_range_dfp_table[0]);
+ tmp_range_table = default_adj_range_dfp_table;
+ break;
+ case CAT_LCD:
+ adj_api->range_table_size = sizeof(default_adj_range_lcd_table)
+ / sizeof(default_adj_range_lcd_table[0]);
+ tmp_range_table = default_adj_range_lcd_table;
+ break;
+ default:
+ break;
+ }
+ if (adj_api->range_table_size > 0)
+ range_alloc_size = adj_api->range_table_size *
+ sizeof(struct range_adjustment_api);
+ if (range_alloc_size > 0 && tmp_range_table != NULL) {
+ adj_api->range_table = dal_alloc(range_alloc_size);
+ if (adj_api->range_table) {
+ for (i = 0; i < adj_api->range_table_size; i++) {
+ dal_memmove(
+ &adj_api->range_table[i],
+ &tmp_range_table[i],
+ sizeof(struct range_adjustment_api));
+ adj_api->range_table[i].flag.bits.
+ def_from_driver = 1;
+ /* not to do read config from reg key*/
+ }
+ }
+ if (adj_api->range_table == NULL) {
+ destruct(adj_api);
+ return false;
+ }
+
+ return true;
+ }
+ /* to do vector table in furture*/
+ return false;
+}
+
+void dal_adj_api_get_api_flag(
+ struct adjustment_api *adj_api,
+ enum adjustment_id adj_id,
+ union adjustment_api_flag *flag)
+{
+ uint32_t i;
+
+ if (adj_api->range_table) {
+ for (i = 0; i < adj_api->range_table_size; i++) {
+ if (adj_api->range_table[i].adj_id == adj_id) {
+ *flag = adj_api->range_table[i].flag;
+ break;
+ }
+ }
+ }
+}
+
+bool dal_adj_api_get_range_adj_data(
+ struct adjustment_api *adj_api,
+ enum adjustment_id adj_id,
+ struct adjustment_info *adj_info)
+{
+ uint32_t i;
+
+ if (adj_api->range_table) {
+ for (i = 0; i < adj_api->range_table_size; i++) {
+ if (adj_api->range_table[i].adj_id == adj_id) {
+ adj_info->adj_data.ranged.def =
+ adj_api->range_table[i].def;
+ adj_info->adj_data.ranged.min =
+ adj_api->range_table[i].min;
+ adj_info->adj_data.ranged.max =
+ adj_api->range_table[i].max;
+ adj_info->adj_data.ranged.step =
+ adj_api->range_table[i].step;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+static bool construct(
+ struct adjustment_api *adj_api,
+ enum adjustment_category category)
+{
+ if (category == CAT_INVALID)
+ return false;
+ adj_api->adj_category = category;
+ adj_api->range_table_size = 0;
+ adj_api->bit_vector_table_size = 0;
+ adj_api->range_table = NULL;
+
+ return true;
+}
+
+static bool parent_api_construct(struct adjustment_parent_api *parent_api)
+{
+ parent_api->api_crt = NULL;
+ parent_api->api_dfp = NULL;
+ parent_api->api_lcd = NULL;
+ return true;
+}
+
+static void parent_api_destruct(struct adjustment_parent_api **parent_api)
+{
+ dal_adj_api_destroy(&(*parent_api)->api_crt);
+ dal_adj_api_destroy(&(*parent_api)->api_dfp);
+ dal_adj_api_destroy(&(*parent_api)->api_lcd);
+}
+
+struct adjustment_api *dal_adj_api_create(enum adjustment_category category)
+{
+ struct adjustment_api *adj_api;
+
+ adj_api = dal_alloc(sizeof(*adj_api));
+
+ if (!adj_api)
+ return NULL;
+ if (construct(adj_api, category))
+ return adj_api;
+
+ dal_free(adj_api);
+ BREAK_TO_DEBUGGER();
+ return NULL;
+}
+
+struct adjustment_parent_api *dal_adj_parent_api_create()
+{
+ struct adjustment_parent_api *parent_api;
+
+ parent_api = dal_alloc(sizeof(*parent_api));
+ if (!parent_api)
+ return NULL;
+ if (parent_api_construct(parent_api))
+ return parent_api;
+
+ dal_free(parent_api);
+ BREAK_TO_DEBUGGER();
+ return NULL;
+}
+
+void dal_adj_parent_api_destroy(struct adjustment_parent_api **parent_api)
+{
+ if (!parent_api || !*parent_api) {
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+ parent_api_destruct(parent_api);
+ dal_free(*parent_api);
+ *parent_api = NULL;
+}
+
+void dal_adj_api_destroy(struct adjustment_api **adj_api)
+{
+ if (!adj_api || !*adj_api) {
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+ destruct(*adj_api);
+ dal_free(*adj_api);
+ *adj_api = NULL;
+}
+
+bool dal_adj_parent_api_build_child_objs(struct adjustment_parent_api *adj_api)
+{
+ adj_api->api_crt = dal_adj_api_create(CAT_CRT);
+ if (!adj_api->api_crt || !build_default_adj_table(adj_api->api_crt))
+ return false;
+
+ adj_api->api_dfp = dal_adj_api_create(CAT_DFP);
+ if (!adj_api->api_dfp || !build_default_adj_table(adj_api->api_dfp))
+ return false;
+
+ adj_api->api_lcd = dal_adj_api_create(CAT_LCD);
+ if (!adj_api->api_lcd || !build_default_adj_table(adj_api->api_lcd))
+ return false;
+ return true;
+}
+
+struct adjustment_api *dal_adj_parent_api_what_is_the_target_obj(
+ struct adjustment_parent_api *adj_api,
+ enum signal_type signal)
+{
+ switch (signal) {
+ case SIGNAL_TYPE_DVI_SINGLE_LINK:
+ case SIGNAL_TYPE_DVI_SINGLE_LINK1:
+ case SIGNAL_TYPE_DVI_DUAL_LINK:
+ case SIGNAL_TYPE_HDMI_TYPE_A:
+ case SIGNAL_TYPE_DISPLAY_PORT:
+ case SIGNAL_TYPE_DISPLAY_PORT_MST:
+ case SIGNAL_TYPE_WIRELESS:
+ return adj_api->api_dfp;
+ case SIGNAL_TYPE_EDP:
+ return adj_api->api_lcd;
+ case SIGNAL_TYPE_RGB:
+ return adj_api->api_crt;
+ default:
+ return NULL;
+ }
+}
diff --git a/drivers/gpu/drm/amd/dal/display_service/adjustment_api.h b/drivers/gpu/drm/amd/dal/display_service/adjustment_api.h
new file mode 100644
index 000000000000..6a1337891dfd
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/adjustment_api.h
@@ -0,0 +1,64 @@
+/*
+ * 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_ADJUSTMENT_API_H__
+#define __DAL_ADJUSTMENT_API_H__
+
+#include "include/adjustment_types.h"
+#include "include/signal_types.h"
+
+struct adjustment_api {
+ enum adjustment_category adj_category;
+ uint32_t range_table_size;
+ uint32_t bit_vector_table_size;
+ struct range_adjustment_api *range_table;
+};
+
+struct adjustment_parent_api {
+ struct adjustment_api *api_crt;
+ struct adjustment_api *api_dfp;
+ struct adjustment_api *api_lcd;
+};
+
+struct adjustment_parent_api *dal_adj_parent_api_create(void);
+
+void dal_adj_parent_api_destroy(struct adjustment_parent_api **parent_api);
+
+struct adjustment_api *dal_adj_parent_api_what_is_the_target_obj(
+ struct adjustment_parent_api *adj_api,
+ enum signal_type signal);
+
+struct adjustment_api *dal_adj_api_create(enum adjustment_category category);
+
+bool dal_adj_parent_api_build_child_objs(struct adjustment_parent_api *adj_api);
+
+void dal_adj_api_destroy(struct adjustment_api **adj_api);
+
+bool dal_adj_api_get_range_adj_data(
+ struct adjustment_api *adj_api,
+ enum adjustment_id adj_id,
+ struct adjustment_info *adj_info);
+
+#endif /* __DAL_ADJUSTMENT_API_H__ */
diff --git a/drivers/gpu/drm/amd/dal/display_service/adjustment_container.c b/drivers/gpu/drm/amd/dal/display_service/adjustment_container.c
new file mode 100644
index 000000000000..41409b144639
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/adjustment_container.c
@@ -0,0 +1,591 @@
+/*
+ * 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/display_path_interface.h"
+#include "include/dcs_interface.h"
+#include "include/fixed31_32.h"
+
+#include "adjustment_container.h"
+
+/*no used for now
+static struct adj_container *get_adj_container_for_path(void)
+{
+ return NULL;
+}
+*/
+void dal_adj_container_update_display_cap(
+ struct adj_container *container,
+ struct display_path *display_path)
+{
+ struct vendor_product_id_info vendor_info = {0};
+ struct cea861_support cea861_support = { 0 };
+ union cea_video_capability_data_block video_cap = { {0} };
+ struct dcs *dcs = dal_display_path_get_dcs(display_path);
+
+ dal_dcs_get_vendor_product_id_info(dcs, &vendor_info);
+ if (!((container->ctx.edid_signature.manufacturer_id ==
+ vendor_info.manufacturer_id) && (container->ctx.
+ edid_signature.product_id == vendor_info.product_id))) {
+ /*new edid,update required */
+ container->ctx.update_required = true;
+ container->ctx.edid_signature = vendor_info;
+ dal_dcs_get_display_characteristics(
+ dcs,
+ &container->ctx.display_characteristics);
+ /* CEA861 support block from edid */
+
+ if (dal_dcs_get_cea861_support(dcs, &cea861_support)) {
+ container->ctx.cea861_support = cea861_support;
+ container->ctx.valid.CEA861_SUPPORT = true;
+ }
+ /* get CEA861 vcblock from edid*/
+ if (dal_dcs_get_cea_video_capability_data_block(
+ dcs, &video_cap)) {
+ container->ctx.vcblock = video_cap;
+ container->ctx.valid.VCBLOCK = true;
+ }
+ }
+}
+
+bool dal_adj_container_get_default_underscan_allow(
+ struct adj_container *container)
+{
+ return container->ctx.flags.NO_DEFAULT_UNDERSCAN;
+}
+
+void dal_adj_container_set_default_underscan_allow(
+ struct adj_container *container,
+ bool restricted)
+{
+ container->ctx.flags.NO_DEFAULT_UNDERSCAN = restricted;
+}
+
+struct adj_container *dal_adj_container_create()
+{
+
+ struct adj_container *container = dal_alloc(sizeof(*container));
+
+ if (!container) {
+ dal_free(container);
+ BREAK_TO_DEBUGGER();
+ return NULL;
+ }
+
+ return container;
+}
+
+void dal_adj_container_destroy(struct adj_container **container)
+{
+ if (!container || !*container) {
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+ dal_free(*container);
+ *container = NULL;
+}
+
+bool dal_adj_container_get_scan_type(
+ const struct adj_container *container,
+ enum scanning_type *scanning_type)
+{
+ if (container->ctx.valid.SCAN_TYPE) {
+ *scanning_type = container->ctx.scan_type;
+ return true;
+ }
+ return false;
+}
+
+bool dal_adj_container_get_display_content_capability(
+ const struct adj_container *container,
+ union display_content_support *support)
+{
+ if (container->ctx.valid.DISP_CONTENT_SUPPORT) {
+ *support = container->ctx.disp_content_support;
+ return true;
+ }
+ return false;
+}
+
+bool dal_adj_container_get_adjustment_val(
+ const struct adj_container *adj_container,
+ enum adjustment_id adj_id,
+ uint32_t *val)
+{
+ /* TODO: implementation of adjustment */
+ return false;
+}
+
+
+void dal_adj_info_set_clear(struct adj_info_set *adj_info_set)
+{
+ dal_memset(
+ adj_info_set->adj_info_array,
+ 0,
+ MAX_ADJUSTMENT_NUM * sizeof(struct adjustment_info));
+}
+
+void dal_adj_info_set_add_adj_info(
+ struct adj_info_set *adj_info_set,
+ struct adjustment_info *adj_info)
+{
+ adj_info_set->adj_info_array[adj_info->adj_id] = *adj_info;
+ adj_info_set->adj_info_array[adj_info->adj_id].adj_state =
+ ADJUSTMENT_STATE_VALID;
+}
+
+static void copy_contents_from(
+ struct adj_info_set *adj_info_set,
+ const struct adj_info_set *adj_info_set_src)
+{
+ uint32_t i;
+
+ for (i = 0; i < MAX_ADJUSTMENT_NUM; i++)
+ adj_info_set->adj_info_array[i] =
+ adj_info_set_src->adj_info_array[i];
+}
+
+struct adjustment_info *dal_adj_info_set_get_adj_info(
+ struct adj_info_set *adj_info_set,
+ enum adjustment_id adj_id)
+{
+ if (adj_id <= ADJ_ID_END && adj_id != ADJ_ID_INVALID) {
+ if (adj_info_set->adj_info_array[adj_id].adj_state !=
+ ADJUSTMENT_STATE_INVALID)
+ return &adj_info_set->adj_info_array[adj_id];
+ }
+ return NULL;
+}
+
+const struct mode_info *dal_adj_container_get_mode_info(
+ struct adj_container *container)
+{
+ return &container->ctx.mode_info;
+}
+
+const struct view *dal_adj_container_get_view(
+ struct adj_container *container)
+{
+ return &container->ctx.view;
+}
+
+void dal_adj_container_update_timing_mode(
+ struct adj_container *container,
+ const struct mode_info *mode_info,
+ const struct view *view)
+{
+ if (mode_info && ((container->ctx.mode_info.field_rate != mode_info->
+ field_rate) || (container->ctx.mode_info.pixel_width !=
+ mode_info->pixel_width) || (container->ctx.mode_info.
+ pixel_height != mode_info->pixel_height) ||
+ (container->ctx.view.height != view->height) ||
+ (container->ctx.view.width !=
+ view->width))) {
+
+ container->ctx.view = *view;
+ container->ctx.mode_info = *mode_info;
+ container->ctx.update_required = true;
+ }
+}
+
+bool dal_adj_container_get_cea861_support(
+ const struct adj_container *container,
+ struct cea861_support *cea861_support)
+{
+ if (container->ctx.cea861_support.revision) {
+ *cea861_support = container->ctx.cea861_support;
+ return true;
+ }
+ return false;
+}
+
+bool dal_adj_container_get_cea_video_cap_data_block(
+ const struct adj_container *container,
+ union cea_video_capability_data_block *vcblock)
+{
+ if (container->ctx.valid.VCBLOCK) {
+ *vcblock = container->ctx.vcblock;
+ return true;
+ }
+ return false;
+}
+
+void dal_adj_container_update_color_space(
+ struct adj_container *container,
+ enum ds_color_space color_space)
+{
+ container->ctx.color_space = color_space;
+ container->ctx.valid.COLOR_SPACE = true;
+}
+
+void dal_adj_container_update_signal_type(
+ struct adj_container *container,
+ enum signal_type signal_type)
+{
+ container->ctx.signal_type = signal_type;
+ container->ctx.valid.SIGNAL_TYPE = true;
+}
+
+enum signal_type dal_adj_container_get_signal_type(
+ struct adj_container *container)
+{
+ if (container->ctx.valid.SIGNAL_TYPE)
+ return container->ctx.signal_type;
+ return SIGNAL_TYPE_NONE;
+}
+
+enum ds_color_space dal_adj_container_get_color_space(
+ const struct adj_container *container)
+{
+ if (container->ctx.valid.COLOR_SPACE)
+ return container->ctx.color_space;
+ return DS_COLOR_SPACE_UNKNOWN;
+}
+
+const struct display_characteristics *dal_adj_container_get_disp_character(
+ struct adj_container *container)
+{
+ if (container->ctx.valid.DISPLAY_CHARACTERISTICS)
+ return &container->ctx.display_characteristics;
+
+ return NULL;
+}
+
+void dal_adj_container_copy_contents_from(
+ struct adj_container *container,
+ struct adj_container *container_src)
+{
+ copy_contents_from(
+ &container->adj_info_set,
+ &container_src->adj_info_set);
+ container->ctx = container_src->ctx;
+}
+
+bool dal_adj_container_commit_adj(
+ struct adj_container *container,
+ enum adjustment_id adj_id)
+{
+ struct adjustment_info *info = dal_adj_info_set_get_adj_info(
+ &container->adj_info_set, adj_id);
+ if (info) {
+ info->adj_state = ADJUSTMENT_STATE_COMMITTED_TO_HW;
+ return true;
+ }
+ return false;
+}
+
+bool dal_adj_container_is_adjustment_committed(
+ struct adj_container *container,
+ enum adjustment_id adj_id)
+{
+ struct adjustment_info *info = dal_adj_info_set_get_adj_info(
+ &container->adj_info_set, adj_id);
+ if (info)
+ return (info->adj_state == ADJUSTMENT_STATE_COMMITTED_TO_HW);
+
+ return false;
+}
+
+bool dal_adj_info_set_get_adj_val(
+ struct adj_info_set *adj_info_set,
+ enum adjustment_id adj_id,
+ int32_t *val)
+{
+ struct adjustment_info *info = dal_adj_info_set_get_adj_info(
+ adj_info_set, adj_id);
+ if (info && val) {
+ *val = info->adj_data.ranged.cur;
+ return true;
+ }
+ return false;
+}
+
+bool dal_adj_info_set_update_cur_value(
+ struct adj_info_set *adj_info_set,
+ enum adjustment_id adj_id,
+ int32_t val)
+{
+ struct adjustment_info *info = dal_adj_info_set_get_adj_info(
+ adj_info_set, adj_id);
+ if (info) {
+ info->adj_data.ranged.cur = val;
+ info->adj_state = ADJUSTMENT_STATE_REQUESTED;
+ return true;
+ }
+ return false;
+}
+
+bool dal_adj_container_is_update_required(struct adj_container *adj_container)
+{
+ return adj_container->ctx.update_required;
+}
+
+void dal_adj_container_updated(struct adj_container *adj_container)
+{
+ adj_container->ctx.update_required = false;
+}
+
+bool dal_adj_container_validate_regamma(
+ struct adj_container *adj_container,
+ const struct ds_regamma_lut *data)
+{
+ uint32_t i;
+
+ struct fixed31_32 a0;
+ struct fixed31_32 a1;
+ struct fixed31_32 a2;
+ struct fixed31_32 a3;
+ struct fixed31_32 gamma;
+ struct fixed31_32 divide;
+ struct fixed31_32 discrete_increment;
+ struct fixed31_32 linear_end;
+ struct fixed31_32 exp_start;
+ bool ret = true;
+
+ if (data->flags.bits.GAMMA_RAMP_ARRAY == 0) {
+ for (i = 0; i < COEFF_RANGE && ret ; i++) {
+ if (data->coeff.coeff_a0[i] == 0 ||
+ data->coeff.coeff_a1[i] == 0 ||
+ data->coeff.coeff_a2[i] == 0 ||
+ data->coeff.coeff_a3[i] == 0 ||
+ data->coeff.gamma[i] == 0) {
+ ret = false;
+ break;
+ }
+
+ a0 = dal_fixed31_32_from_int(
+ (int64_t)data->coeff.coeff_a0[i]);
+ a1 = dal_fixed31_32_from_int(
+ (int64_t)data->coeff.coeff_a1[i]);
+ a2 = dal_fixed31_32_from_int(
+ (int64_t)data->coeff.coeff_a2[i]);
+ a3 = dal_fixed31_32_from_int(
+ (int64_t)data->coeff.coeff_a3[i]);
+ gamma = dal_fixed31_32_from_int(
+ (int64_t)data->coeff.gamma[i]);
+
+ a0 = dal_fixed31_32_div_int(
+ a0, ADJUST_DIVIDER_2);
+ a1 = dal_fixed31_32_div_int(
+ a1, ADJUST_DIVIDER_1);
+ a2 = dal_fixed31_32_div_int(
+ a2, ADJUST_DIVIDER_1);
+ a3 = dal_fixed31_32_div_int(
+ a3, ADJUST_DIVIDER_1);
+ gamma = dal_fixed31_32_div_int(
+ gamma, ADJUST_DIVIDER_1);
+
+ divide = dal_fixed31_32_one;
+ discrete_increment = dal_fixed31_32_one;
+
+ if (dal_fixed31_32_lt(
+ dal_fixed31_32_from_int(
+ (int64_t)REGAMMA_CONSTANT_1),
+ dal_fixed31_32_div(divide, a0)))
+ discrete_increment = dal_fixed31_32_div_int(
+ discrete_increment, 8192);
+ else if (dal_fixed31_32_lt(
+ dal_fixed31_32_from_int(
+ (int64_t)REGAMMA_CONSTANT_2),
+ dal_fixed31_32_div(divide, a0)))
+ discrete_increment = dal_fixed31_32_div_int(
+ discrete_increment, 4096);
+ else if (dal_fixed31_32_lt(
+ dal_fixed31_32_from_int(
+ (int64_t)REGAMMA_CONSTANT_3),
+ dal_fixed31_32_div(divide, a0)))
+ discrete_increment = dal_fixed31_32_div_int(
+ discrete_increment, 2048);
+ else
+ discrete_increment = dal_fixed31_32_div_int(
+ discrete_increment, 1024);
+
+ linear_end = dal_fixed31_32_mul(
+ dal_fixed31_32_sub(
+ a0, discrete_increment), a1);
+
+ discrete_increment = dal_fixed31_32_one;
+ exp_start = dal_fixed31_32_div(
+ discrete_increment, gamma);
+ exp_start = dal_fixed31_32_pow(a0, exp_start);
+
+ exp_start = dal_fixed31_32_mul(
+ (dal_fixed31_32_add(
+ discrete_increment, a3)),
+ exp_start);
+
+ exp_start = dal_fixed31_32_sub(
+ exp_start, a2);
+
+ if (dal_fixed31_32_lt(
+ exp_start, linear_end)) {
+ ret = false;
+ break;
+ }
+ }
+ } else {
+ for (i = 1; i < REGAMMA_VALUE ; i++) {
+ if (data->gamma.gamma[i] < data->gamma.gamma[i-1]) {
+ ret = false;
+ break;
+ }
+ if (data->gamma.gamma[i+256] <
+ data->gamma.gamma[i-1+256]) {
+ ret = false;
+ break;
+ }
+ if (data->gamma.gamma[i+512] <
+ data->gamma.gamma[i-1+512]) {
+ ret = false;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+bool dal_adj_container_set_regamma(
+ struct adj_container *adj_container,
+ const struct ds_regamma_lut *regamma)
+{
+ if (!dal_adj_container_validate_regamma(
+ adj_container, regamma))
+ return false;
+
+ adj_container->ctx.valid.REGAMMA = true;
+ adj_container->ctx.regamma = *regamma;
+
+ return true;
+}
+
+const struct ds_regamma_lut *dal_adj_container_get_regamma(
+ struct adj_container *adj_container)
+{
+
+ if (adj_container->ctx.valid.REGAMMA == true)
+ return &adj_container->ctx.regamma;
+ return NULL;
+}
+
+bool dal_adj_container_get_gamut(
+ struct adj_container *adj_container,
+ enum adjustment_id adj_id,
+ struct gamut_data *data)
+{
+ bool ret = false;
+
+ switch (adj_id) {
+ case ADJ_ID_GAMUT_SOURCE_GRPH:
+ if (adj_container->ctx.valid.GAMUT_SRC_GRPH == true) {
+ *data = adj_container->ctx.gamut_src_grph;
+ ret = true;
+ }
+ break;
+ case ADJ_ID_GAMUT_SOURCE_OVL:
+ if (adj_container->ctx.valid.GAMUT_SRC_OVL == true) {
+ *data = adj_container->ctx.gamut_src_ovl;
+ ret = true;
+ }
+ break;
+ case ADJ_ID_GAMUT_DESTINATION:
+ if (adj_container->ctx.valid.GAMUT_DST == true) {
+ *data = adj_container->ctx.gamut_dst;
+ ret = true;
+ }
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+bool dal_adj_container_validate_gamut(
+ struct adj_container *adj_container,
+ struct gamut_data *data)
+{
+ if (data->option.bits.CUSTOM_GAMUT_SPACE == 1) {
+ if (data->gamut.custom.red_x == 0 ||
+ data->gamut.custom.red_y == 0 ||
+ data->gamut.custom.green_x == 0 ||
+ data->gamut.custom.green_y == 0 ||
+ data->gamut.custom.blue_x == 0 ||
+ data->gamut.custom.blue_y == 0)
+ return false;
+ } else
+ if (data->gamut.predefined.u32all == 0)
+ return false;
+
+ if (data->option.bits.CUSTOM_WHITE_POINT == 1) {
+ if (data->white_point.custom.white_x == 0 ||
+ data->white_point.custom.white_y == 0)
+ return false;
+ } else
+ if (data->white_point.predefined.u32all == 0)
+ return false;
+
+ return true;
+}
+
+bool dal_adj_container_update_gamut(
+ struct adj_container *adj_container,
+ enum adjustment_id adj_id,
+ struct gamut_data *data)
+{
+ if (!dal_adj_container_validate_gamut(
+ adj_container, data))
+ return false;
+
+ switch (adj_id) {
+ case ADJ_ID_GAMUT_SOURCE_GRPH:
+ adj_container->ctx.gamut_src_grph = *data;
+ adj_container->ctx.valid.GAMUT_SRC_GRPH = true;
+ break;
+ case ADJ_ID_GAMUT_SOURCE_OVL:
+ adj_container->ctx.gamut_src_ovl = *data;
+ adj_container->ctx.valid.GAMUT_SRC_OVL = true;
+ break;
+ case ADJ_ID_GAMUT_DESTINATION:
+ adj_container->ctx.gamut_dst = *data;
+ adj_container->ctx.valid.GAMUT_DST = true;
+ break;
+ default:
+ adj_container->ctx.valid.GAMUT_SRC_GRPH = false;
+ adj_container->ctx.valid.GAMUT_SRC_OVL = false;
+ adj_container->ctx.valid.GAMUT_DST = false;
+ break;
+ }
+ return true;
+}
+
+bool dal_adj_container_get_regamma_copy(
+ struct adj_container *adj_container,
+ struct ds_regamma_lut *regamma)
+{
+ if (adj_container->ctx.valid.REGAMMA == true) {
+ *regamma = adj_container->ctx.regamma;
+ return true;
+ }
+ return false;
+}
diff --git a/drivers/gpu/drm/amd/dal/display_service/adjustment_container.h b/drivers/gpu/drm/amd/dal/display_service/adjustment_container.h
new file mode 100644
index 000000000000..5bc12aca54ab
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/adjustment_container.h
@@ -0,0 +1,207 @@
+/*
+ * 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_ADJUSTMENT_CONTAINER_H__
+#define __DAL_ADJUSTMENT_CONTAINER_H__
+
+#include "include/adjustment_types.h"
+#include "include/dcs_types.h"
+#include "include/timing_service_types.h"
+#include "include/set_mode_types.h"
+#include "include/signal_types.h"
+#include "display_service/adjustment_types_internal.h"
+
+#define ADJUST_DIVIDER_1 1000
+#define ADJUST_DIVIDER_2 10000000
+#define REGAMMA_CONSTANT_1 256
+#define REGAMMA_CONSTANT_2 128
+#define REGAMMA_CONSTANT_3 64
+
+struct adj_info_set {
+ struct adjustment_info adj_info_array[MAX_ADJUSTMENT_NUM];
+};
+
+struct adj_container {
+ /* to-do,not 100% be ported */
+ struct adj_info_set adj_info_set;
+
+ struct {
+ bool update_required;
+ struct mode_info mode_info;
+ struct view view;
+ struct cea861_support cea861_support;
+ struct vendor_product_id_info edid_signature;
+ struct display_characteristics display_characteristics;
+ union cea_video_capability_data_block vcblock;
+ enum ds_color_space color_space;
+ enum signal_type signal_type;
+ enum scanning_type scan_type;
+ union display_content_support disp_content_support;
+ struct gamut_data gamut_src_grph;
+ struct gamut_data gamut_src_ovl;
+ struct gamut_data gamut_dst;
+ struct ds_regamma_lut regamma;
+
+ struct {
+ bool DISPLAY_CHARACTERISTICS:1;
+ bool COLOR_SPACE:1;
+ bool VCBLOCK:1;
+ bool CEA861_SUPPORT:1;
+ bool SIGNAL_TYPE:1;
+ bool SCAN_TYPE:1;
+ bool GAMUT_SRC_GRPH:1;
+ bool GAMUT_SRC_OVL:1;
+ bool GAMUT_DST:1;
+ bool REGAMMA:1;
+ bool DISP_CONTENT_SUPPORT:1;
+ } valid;
+ struct {
+ bool NO_DEFAULT_UNDERSCAN:1;
+ } flags;
+ } ctx;
+};
+
+union display_content_support;
+
+bool dal_adj_container_get_default_underscan_allow(
+ struct adj_container *container);
+
+void dal_adj_container_update_display_cap(
+ struct adj_container *container,
+ struct display_path *display_path);
+
+void dal_adj_container_set_default_underscan_allow(
+ struct adj_container *container,
+ bool restricted);
+
+void dal_adj_container_destroy(struct adj_container **container);
+
+const struct display_characteristics *dal_adj_container_get_disp_character(
+ struct adj_container *container);
+
+enum ds_color_space dal_adj_container_get_color_space(
+ const struct adj_container *container);
+
+enum signal_type dal_adj_container_get_signal_type(
+ struct adj_container *container);
+
+void dal_adj_container_update_color_space(
+ struct adj_container *container,
+ enum ds_color_space color_space);
+
+void dal_adj_container_update_signal_type(
+ struct adj_container *container,
+ enum signal_type signal_type);
+
+bool dal_adj_container_get_cea861_support(
+ const struct adj_container *container,
+ struct cea861_support *cea861_support);
+
+bool dal_adj_container_get_cea_video_cap_data_block(
+ const struct adj_container *container,
+ union cea_video_capability_data_block *vcblock);
+
+const struct mode_info *dal_adj_container_get_mode_info(
+ struct adj_container *container);
+
+const struct view *dal_adj_container_get_view(
+ struct adj_container *container);
+
+bool dal_adj_container_is_adjustment_committed(
+ struct adj_container *container,
+ enum adjustment_id adj_id);
+
+bool dal_adj_container_commit_adj(
+ struct adj_container *container,
+ enum adjustment_id adj_id);
+
+void dal_adj_container_updated(struct adj_container *adj_container);
+
+struct adj_container *dal_adj_container_create(void);
+
+struct adjustment_info *dal_adj_info_set_get_adj_info(
+ struct adj_info_set *adj_info_set,
+ enum adjustment_id adj_id);
+
+bool dal_adj_container_get_scan_type(
+ const struct adj_container *adj_container,
+ enum scanning_type *scanning_type);
+
+/* TODO: implementation of adjustment */
+bool dal_adj_container_get_display_content_capability(
+ const struct adj_container *adj_container,
+ union display_content_support *support);
+
+/* TODO: implementation of adjustment */
+bool dal_adj_container_get_adjustment_val(
+ const struct adj_container *adj_container,
+ enum adjustment_id adj_id,
+ uint32_t *val);
+
+bool dal_adj_info_set_update_cur_value(
+ struct adj_info_set *adj_info_set,
+ enum adjustment_id adj_id,
+ int32_t val);
+
+bool dal_adj_container_is_update_required(
+ struct adj_container *adj_container);
+
+void dal_adj_info_set_add_adj_info(
+ struct adj_info_set *adj_info_set,
+ struct adjustment_info *adj_info);
+
+void dal_adj_info_set_clear(struct adj_info_set *adj_info_set);
+
+void dal_adj_container_update_timing_mode(
+ struct adj_container *container,
+ const struct mode_info *mode_info,
+ const struct view *view);
+
+bool dal_adj_container_set_regamma(
+ struct adj_container *adj_container,
+ const struct ds_regamma_lut *regamma);
+
+bool dal_adj_container_get_gamut(
+ struct adj_container *adj_container,
+ enum adjustment_id adj_id,
+ struct gamut_data *data);
+
+const struct ds_regamma_lut *dal_adj_container_get_regamma(
+ struct adj_container *adj_container);
+
+bool dal_adj_container_validate_gamut(
+ struct adj_container *adj_container,
+ struct gamut_data *data);
+
+bool dal_adj_container_update_gamut(
+ struct adj_container *adj_container,
+ enum adjustment_id adj_id,
+ struct gamut_data *data);
+
+bool dal_adj_container_get_regamma_copy(
+ struct adj_container *adj_container,
+ struct ds_regamma_lut *regamma);
+
+#endif /* __DAL_ADJUSTMENT_CONTAINER_H__ */
diff --git a/drivers/gpu/drm/amd/dal/display_service/adjustment_types_internal.h b/drivers/gpu/drm/amd/dal/display_service/adjustment_types_internal.h
new file mode 100644
index 000000000000..31180d049e97
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/adjustment_types_internal.h
@@ -0,0 +1,198 @@
+/*
+ * 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_ADJUSTMENT_TYPES_INTERNAL_H__
+#define __DAL_ADJUSTMENT_TYPES_INTERNAL_H__
+
+#include "include/adjustment_types.h"
+#include "include/set_mode_types.h"
+#include "include/hw_sequencer_types.h"
+#include "include/timing_service_types.h"
+
+struct underscan_adjustment_group {
+ enum adjustment_id id_overscan;
+ enum adjustment_id id_underscan;
+ enum adjustment_id id_underscan_auto;
+ enum adjustment_id id_multi_media_pass_thru;
+ enum adjustment_id id_tv_underscan;
+ enum adjustment_id id_requested;
+
+ union adjustment_property prop_overscan;
+ union adjustment_property prop_underscan;
+ union adjustment_property prop_underscan_auto;
+ union adjustment_property prop_multi_media_pass_thru;
+ union adjustment_property prop_tv_underscan;
+
+ int32_t requested_value;
+ int32_t current_overscan;
+ int32_t current_percent_x;
+ int32_t current_percent_y;
+ int32_t current_underscan_auto;
+ int32_t current_multi_media_pass_thru;
+ struct ds_underscan_desc current_underscan_desc;
+};
+
+struct timing_info_parameter {
+ struct hw_crtc_timing timing;
+ uint32_t dst_width;
+ uint32_t dst_height;
+};
+/* Display content type as flag */
+enum display_content_type {
+ DISPLAY_CONTENT_TYPE_NO_DATA = 0,
+ DISPLAY_CONTENT_TYPE_GRAPHICS = 1,
+ DISPLAY_CONTENT_TYPE_PHOTO = 2,
+ DISPLAY_CONTENT_TYPE_CINEMA = 4,
+ DISPLAY_CONTENT_TYPE_GAME = 8
+};
+
+union display_content_support {
+ uint32_t raw;
+ struct {
+ uint32_t VALID_CONTENT_TYPE:1;
+ uint32_t GAME_CONTENT:1;
+ uint32_t CINEMA_CONTENT:1;
+ uint32_t PHOTO_CONTENT:1;
+ uint32_t GRAPHICS_CONTENT:1;
+ uint32_t RESERVED:27;
+ } bits;
+};
+
+/* to-do regkey if android supported*/
+union adjustment_api_flag {
+ uint32_t value;
+ struct {
+ uint32_t def_from_driver:1;
+ uint32_t reserved:31;
+ } bits;
+};
+
+struct range_adjustment_api {
+ enum adjustment_id adj_id;
+ int32_t def;
+ int32_t min;
+ int32_t max;
+ int32_t step;
+ union adjustment_api_flag flag;
+};
+
+union ds_scaler_flags {
+ uint32_t val;
+ struct {
+ uint32_t VALID_DS_MODE:1;
+ uint32_t IS_FOR_SET_MODE:1;
+ uint32_t IS_TV:1;
+ uint32_t IS_UNDERSCAN_DESC:1;
+ uint32_t RESERVED28:28;
+ } bits;
+};
+
+struct ds_adjustment_scaler {
+ uint32_t display_index;
+ enum adjustment_id adjust_id;
+ int32_t value;
+ enum timing_standard timing_standard;
+ enum timing_source timing_source;
+ struct ds_underscan_desc underscan_desc;
+ union ds_scaler_flags flags;
+};
+
+struct ds_adjustment_status {
+ uint32_t val;
+ struct {
+ uint32_t SET_TO_DEFAULT:1;
+ uint32_t SET_FROM_EXTERNAL:1;
+ uint32_t SET_TO_HARDWARE:1;
+ uint32_t RESERVED:29;
+ } bits;
+};
+
+enum ds_underscan_type {
+ DS_UNDERSCAN_TYPE_PERCENT,
+ DS_UNDERSCAN_TYPE_DIMENTIONS,
+};
+
+struct ds_underscan_data {
+ uint32_t position_x;
+ uint32_t position_y;
+ uint32_t width;
+ uint32_t height;
+};
+
+struct ds_underscan_percent {
+ uint32_t percent_x;
+ uint32_t percent_y;
+ uint32_t old_dst_x;
+ uint32_t old_dst_y;
+};
+
+struct ds_underscan_data_parameter {
+ struct ds_underscan_data data;
+ uint32_t modified_boarder_x;
+ uint32_t modified_boarder_y;
+};
+
+struct ds_underscan_parameter {
+ enum ds_underscan_type type;
+ union {
+ struct ds_underscan_data_parameter dimentions;
+ struct ds_underscan_percent percent;
+ } data;
+};
+
+enum ds_bit_depth_reduction {
+ DS_BIT_DEPTH_REDUCTION_DISABLE = 0,
+ DS_BIT_DEPTH_REDUCTION_DRIVER_DEFAULT,
+ DS_BIT_DEPTH_REDUCTION_FM6,
+ DS_BIT_DEPTH_REDUCTION_FM8,
+ DS_BIT_DEPTH_REDUCTION_FM10,
+ DS_BIT_DEPTH_REDUCTION_DITH6,
+ DS_BIT_DEPTH_REDUCTION_DITH8,
+ DS_BIT_DEPTH_REDUCTION_DITH10,
+ DS_BIT_DEPTH_REDUCTION_DITH6_NO_FRAME_RAND,
+ DS_BIT_DEPTH_REDUCTION_DITH8_NO_FRAME_RAND,
+ DS_BIT_DEPTH_REDUCTION_DITH10_NO_FRAME_RAND,
+ DS_BIT_DEPTH_REDUCTION_TRUN6,
+ DS_BIT_DEPTH_REDUCTION_TRUN8,
+ DS_BIT_DEPTH_REDUCTION_TRUN10,
+ DS_BIT_DEPTH_REDUCTION_TRUN10_DITH8,
+ DS_BIT_DEPTH_REDUCTION_TRUN10_DITH6,
+ DS_BIT_DEPTH_REDUCTION_TRUN10_FM8,
+ DS_BIT_DEPTH_REDUCTION_TRUN10_FM6,
+ DS_BIT_DEPTH_REDUCTION_TRUN10_DITH8_FM6,
+ DS_BIT_DEPTH_REDUCTION_DITH10_FM8,
+ DS_BIT_DEPTH_REDUCTION_DITH10_FM6,
+ DS_BIT_DEPTH_REDUCTION_TRUN8_DITH6,
+ DS_BIT_DEPTH_REDUCTION_TRUN8_FM6,
+ DS_BIT_DEPTH_REDUCTION_DITH8_FM6, /* =23 */
+
+ DS_BIT_DEPTH_REDUCTION_MAX = DS_BIT_DEPTH_REDUCTION_DITH8_FM6
+};
+
+enum color_temperature_source {
+ COLOR_TEMPERATURE_SOURCE_EDID = 1,
+ COLOR_TEMPERATURE_SOURCE_USER
+};
+
+#endif /* __DAL_ADJUSTMENT_TYPES_INTERNAL_H__ */
diff --git a/drivers/gpu/drm/amd/dal/display_service/backlight_adj_group.c b/drivers/gpu/drm/amd/dal/display_service/backlight_adj_group.c
new file mode 100644
index 000000000000..0952ebd5f013
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/backlight_adj_group.c
@@ -0,0 +1,500 @@
+/*
+ * 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 "include/display_path_interface.h"
+#include "include/display_service_types.h"
+#include "include/hw_adjustment_types.h"
+#include "include/adjustment_interface.h"
+#include "include/logger_interface.h"
+#include "include/hw_adjustment_set.h"
+
+#include "ds_dispatch.h"
+#include "adjustment_container.h"
+#include "backlight_adj_group.h"
+
+static uint32_t adj_id_to_cache_index(
+ enum adjustment_id adj_id)
+{
+ if (adj_id == ADJ_ID_BACKLIGHT)
+ return BI_ADJ_INDEX_BACKLIGHT;
+ else if (adj_id == ADJ_ID_BACKLIGHT_OPTIMIZATION)
+ return BI_ADJ_INDEX_BACKLIGHT_OPTIMIZATION;
+
+ return -1;
+}
+
+bool dal_backlight_adj_group_add_adj_to_post_mode_set(
+ struct backlight_adj_group *backlight_adj,
+ uint32_t value,
+ struct hw_adjustment_set *set)
+{
+ struct hw_adjustment_value *adj_value = NULL;
+
+ if (set->backlight != NULL) {
+ dal_logger_write(
+ backlight_adj->dal_context->logger,
+ LOG_MAJOR_WARNING,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "HW Backlight adjustment is NULL");
+ return false;
+ }
+ adj_value = dal_alloc(sizeof(*adj_value));
+
+ if (!adj_value)
+ return false;
+
+ adj_value->i_value = value;
+ set->backlight = adj_value;
+
+ return true;
+
+}
+bool dal_backlight_adj_group_include_backlight_opt_adj(
+ struct backlight_adj_group *backlight_adj,
+ struct display_path *disp_path,
+ uint32_t value,
+ struct hw_adjustment_set *set)
+{
+ uint32_t count = 0;
+
+ switch (value) {
+ case DS_BACKLIGHT_OPTIMIZATION_DISABLE:
+ {
+ uint32_t backlight;
+
+ if (dal_backlight_adj_group_get_current_adj(
+ backlight_adj,
+ disp_path,
+ ADJ_ID_BACKLIGHT,
+ false,
+ &backlight)) {
+ if (dal_backlight_adj_group_add_adj_to_post_mode_set(
+ backlight_adj,
+ backlight,
+ set))
+ count++;
+ }
+ if (dal_backlight_adj_group_add_adj_to_post_mode_set(
+ backlight_adj,
+ 0,
+ set))
+ count++;
+ }
+ break;
+ case DS_BACKLIGHT_OPTIMIZATION_DESKTOP:
+ case DS_BACKLIGHT_OPTIMIZATION_DYNAMIC:
+ {
+ uint32_t backlight;
+
+ if (dal_backlight_adj_group_get_current_adj(
+ backlight_adj,
+ disp_path,
+ ADJ_ID_BACKLIGHT,
+ false,
+ &backlight)) {
+ if (dal_backlight_adj_group_add_adj_to_post_mode_set(
+ backlight_adj,
+ backlight,
+ set))
+ count++;
+ }
+
+ }
+ break;
+ case DS_BACKLIGHT_OPTIMIZATION_DIMMED:
+ {
+ struct panel_backlight_boundaries boundaries = {0};
+
+ if (dal_adapter_service_get_panel_backlight_boundaries(
+ backlight_adj->as,
+ &boundaries)) {
+ if (dal_backlight_adj_group_add_adj_to_post_mode_set(
+ backlight_adj,
+ boundaries.min_signal_level,
+ set))
+ count++;
+ }
+ if (dal_backlight_adj_group_add_adj_to_post_mode_set(
+ backlight_adj,
+ 0,
+ set))
+ count++;
+ }
+ break;
+ default:
+ break;
+ }
+ if (count > 0)
+ return true;
+ else
+ return false;
+}
+
+bool dal_backlight_adj_group_include_post_set_mode_adj(
+ struct backlight_adj_group *backlight_adj,
+ struct display_path *disp_path,
+ struct ds_adj_id_value adj,
+ struct hw_adjustment_set *set)
+{
+ uint32_t index = adj_id_to_cache_index(adj.adj_id);
+ uint32_t opt_adjustment = 0;
+ bool result = false;
+ uint32_t value = backlight_adj->cache[index].value;
+
+ if (index >= NUM_OF_BACKLIGHT_ADJUSTMENTS)
+ return false;
+
+ if (!backlight_adj->cache[index].pending)
+ return false;
+
+
+ if (adj.adj_id != ADJ_ID_BACKLIGHT_OPTIMIZATION) {
+ if (!dal_backlight_adj_group_get_current_adj(
+ backlight_adj,
+ disp_path,
+ ADJ_ID_BACKLIGHT_OPTIMIZATION,
+ true,
+ &opt_adjustment))
+ return false;
+ }
+
+ switch (adj.adj_id) {
+ case ADJ_ID_BACKLIGHT:
+ {
+ if (opt_adjustment != DS_BACKLIGHT_OPTIMIZATION_DIMMED)
+ result =
+ dal_backlight_adj_group_add_adj_to_post_mode_set(
+ backlight_adj,
+ value,
+ set);
+ }
+ break;
+ case ADJ_ID_BACKLIGHT_OPTIMIZATION:
+ {
+ result =
+ dal_backlight_adj_group_include_backlight_opt_adj(
+ backlight_adj,
+ disp_path,
+ value,
+ set);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (backlight_adj->cache[index].pending_sw_commit) {
+ uint32_t display_index =
+ dal_display_path_get_display_index(disp_path);
+ struct adj_container *adj_container =
+ dal_ds_dispatch_get_adj_container_for_path(
+ backlight_adj->ds, display_index);
+ const struct adjustment_info *adj_info = NULL;
+
+ bool commit = (adj_container != NULL);
+
+ if (commit) {
+ adj_info = dal_adj_info_set_get_adj_info(
+ &adj_container->adj_info_set,
+ adj.adj_id);
+
+ commit = (adj_info != NULL);
+ }
+ if (commit)
+ commit = dal_adj_info_set_update_cur_value(
+ &adj_container->adj_info_set,
+ adj.adj_id, value);
+
+ if (commit)
+ commit = dal_adj_container_commit_adj(
+ adj_container, adj.adj_id);
+ }
+ backlight_adj->cache[index].pending = false;
+ backlight_adj->cache[index].pending_sw_commit = false;
+ return result;
+}
+
+
+enum ds_return dal_backlight_adj_group_set_adjustment(
+ struct backlight_adj_group *backlight_adj,
+ struct display_path *disp_path,
+ enum adjustment_id adj_id,
+ uint32_t value)
+{
+ enum ds_return result = DS_SUCCESS;
+ uint32_t display_index =
+ dal_display_path_get_display_index(disp_path);
+ uint32_t adj_index = adj_id_to_cache_index(adj_id);
+
+ struct adj_container *adj_container =
+ dal_ds_dispatch_get_adj_container_for_path(
+ backlight_adj->ds,
+ display_index);
+ const struct adjustment_info *adj_info =
+ dal_adj_info_set_get_adj_info(
+ &adj_container->adj_info_set, adj_id);
+ uint32_t opt_adj = 0;
+
+ if (adj_container == NULL ||
+ adj_index >= NUM_OF_BACKLIGHT_ADJUSTMENTS)
+ return DS_ERROR;
+
+
+ if (adj_info == NULL) {
+
+ struct adjustment_info default_adj_info;
+
+ if (dal_ds_dispatch_get_adjustment_info(
+ backlight_adj->ds,
+ display_index,
+ adj_id,
+ &default_adj_info) != DS_SUCCESS)
+ return DS_ERROR;
+
+ if (value < default_adj_info.adj_data.ranged.min ||
+ value > default_adj_info.adj_data.ranged.max)
+ return DS_ERROR;
+ backlight_adj->cache[adj_index].pending = true;
+ backlight_adj->cache[adj_index].pending_sw_commit = true;
+ backlight_adj->cache[adj_index].value = value;
+ return DS_SUCCESS;
+ }
+ if (value < adj_info->adj_data.ranged.min ||
+ value > adj_info->adj_data.ranged.max)
+ return DS_ERROR;
+
+ if (!dal_adj_info_set_update_cur_value(
+ &adj_container->adj_info_set, adj_id, value))
+ return DS_ERROR;
+
+ if (adj_id != ADJ_ID_BACKLIGHT_OPTIMIZATION) {
+ if (!dal_backlight_adj_group_get_current_adj(
+ backlight_adj,
+ disp_path,
+ ADJ_ID_BACKLIGHT_OPTIMIZATION,
+ true, &opt_adj))
+ return DS_ERROR;
+ }
+
+ if (dal_display_path_is_acquired(disp_path) &&
+ dal_tm_is_hw_state_valid(backlight_adj->tm)) {
+
+ switch (adj_id) {
+ case ADJ_ID_BACKLIGHT:
+ {
+ if (opt_adj != DS_BACKLIGHT_OPTIMIZATION_DIMMED)
+ result =
+ dal_backlight_adj_group_set_backlight_adj(
+ backlight_adj,
+ disp_path,
+ value);
+ }
+ break;
+ case ADJ_ID_BACKLIGHT_OPTIMIZATION:
+ {
+ result =
+ dal_backlight_adj_group_set_backlight_optimization_adj(
+ backlight_adj,
+ disp_path,
+ value);
+ }
+ break;
+ default:
+ result = DS_ERROR;
+ break;
+ }
+ backlight_adj->cache[adj_index].pending = false;
+ backlight_adj->cache[adj_index].pending_sw_commit = false;
+ } else {
+ backlight_adj->cache[adj_index].pending = true;
+ backlight_adj->cache[adj_index].pending_sw_commit = false;
+ backlight_adj->cache[adj_index].value = value;
+ }
+ if (result == DS_SUCCESS)
+ dal_adj_container_commit_adj(adj_container, adj_id);
+ return result;
+}
+
+bool dal_backlight_adj_group_get_current_adj(
+ struct backlight_adj_group *backlight_adj,
+ struct display_path *disp_path,
+ enum adjustment_id adj_id,
+ bool allow_default,
+ uint32_t *value)
+{
+ uint32_t index = adj_id_to_cache_index(adj_id);
+
+ if (backlight_adj->cache[index].pending) {
+ *value = backlight_adj->cache[index].value;
+ return true;
+ } else if (dal_ds_dispatch_get_adjustment_value(
+ backlight_adj->ds,
+ disp_path,
+ adj_id,
+ allow_default,
+ value) == DS_SUCCESS)
+ return true;
+
+ return false;
+}
+
+enum ds_return dal_backlight_adj_group_set_backlight_adj(
+ struct backlight_adj_group *backlight_adj,
+ struct display_path *disp_path,
+ uint32_t value)
+{
+ enum ds_return result = DS_ERROR;
+ struct hw_adjustment_value hw_adj_value;
+
+ hw_adj_value.ui_value = value;
+ if (dal_hw_sequencer_set_backlight_adjustment(
+ backlight_adj->hws,
+ disp_path,
+ &hw_adj_value) == HWSS_RESULT_OK)
+ result = DS_SUCCESS;
+
+ return result;
+}
+
+enum ds_return dal_backlight_adj_group_set_backlight_optimization_adj(
+ struct backlight_adj_group *backlight_adj,
+ struct display_path *disp_path,
+ uint32_t value)
+{
+ switch (value) {
+ case DS_BACKLIGHT_OPTIMIZATION_DISABLE:
+ {
+ uint32_t backlight;
+
+ if (dal_backlight_adj_group_get_current_adj(
+ backlight_adj,
+ disp_path,
+ ADJ_ID_BACKLIGHT,
+ false,
+ &backlight)) {
+
+ if (dal_backlight_adj_group_set_backlight_adj(
+ backlight_adj,
+ disp_path,
+ backlight) != DS_SUCCESS)
+ return DS_ERROR;
+ }
+ }
+ break;
+ case DS_BACKLIGHT_OPTIMIZATION_DESKTOP:
+ case DS_BACKLIGHT_OPTIMIZATION_DYNAMIC:
+ {
+ uint32_t backlight;
+
+ if (dal_backlight_adj_group_get_current_adj(
+ backlight_adj,
+ disp_path,
+ ADJ_ID_BACKLIGHT,
+ false,
+ &backlight)) {
+ if (dal_backlight_adj_group_set_backlight_adj(
+ backlight_adj,
+ disp_path,
+ backlight) != DS_SUCCESS)
+ return DS_ERROR;
+ }
+
+ }
+ break;
+ case DS_BACKLIGHT_OPTIMIZATION_DIMMED:
+ {
+ struct panel_backlight_boundaries boundaries = {0};
+ uint32_t backlight;
+
+ if (!dal_adapter_service_get_panel_backlight_boundaries(
+ backlight_adj->as,
+ &boundaries))
+ return DS_ERROR;
+
+ backlight = boundaries.min_signal_level;
+ if (dal_backlight_adj_group_set_backlight_adj(
+ backlight_adj,
+ disp_path,
+ backlight) != DS_SUCCESS)
+ return DS_ERROR;
+
+ }
+ break;
+ default:
+ return DS_ERROR;
+ }
+ return DS_SUCCESS;
+
+}
+
+static bool backlight_adj_group_construct(
+ struct backlight_adj_group *backlight_adj,
+ struct backlight_adj_group_init_data *init_data)
+{
+ if (!init_data)
+ return false;
+
+ backlight_adj->ds = init_data->ds;
+ backlight_adj->as = init_data->as;
+ backlight_adj->hws = init_data->hws;
+ backlight_adj->tm = init_data->tm;
+ backlight_adj->dal_context = init_data->dal_context;
+
+ return true;
+}
+
+struct backlight_adj_group *dal_backlight_adj_group_create(
+ struct backlight_adj_group_init_data *init_data)
+{
+ struct backlight_adj_group *backlight_adj = NULL;
+
+ backlight_adj = dal_alloc(sizeof(*backlight_adj));
+
+ if (!backlight_adj)
+ return NULL;
+
+ if (backlight_adj_group_construct(backlight_adj, init_data))
+ return backlight_adj;
+
+ dal_free(backlight_adj);
+
+ return NULL;
+}
+
+static void destruct(
+ struct backlight_adj_group *backlight_adj)
+{
+}
+
+void dal_backlight_adj_group_destroy(
+ struct backlight_adj_group **backlight_adj)
+{
+ if (backlight_adj == NULL || *backlight_adj == NULL)
+ return;
+ destruct(*backlight_adj);
+ dal_free(*backlight_adj);
+ *backlight_adj = NULL;
+}
diff --git a/drivers/gpu/drm/amd/dal/display_service/backlight_adj_group.h b/drivers/gpu/drm/amd/dal/display_service/backlight_adj_group.h
new file mode 100644
index 000000000000..ff23040e8425
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/backlight_adj_group.h
@@ -0,0 +1,97 @@
+/*
+ * 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_BACKLIGHT_ADJ_GROUP_H__
+#define __DAL_BACKLIGHT_ADJ_GROUP_H__
+
+/* Include */
+#include "include/adjustment_types.h"
+
+
+#define NUM_OF_BACKLIGHT_ADJUSTMENTS 4
+
+struct adj_catch {
+ uint32_t value;
+ bool pending;
+ bool pending_sw_commit;
+};
+enum bi_adj_index {
+ BI_ADJ_INDEX_BACKLIGHT = 0,
+ BI_ADJ_INDEX_BACKLIGHT_OPTIMIZATION
+};
+
+struct backlight_adj_group {
+ struct ds_dispatch *ds;
+ struct topology_mgr *tm;
+ struct hw_sequencer *hws;
+ struct adapter_service *as;
+ struct dal_context *dal_context;
+ struct adj_catch cache[NUM_OF_BACKLIGHT_ADJUSTMENTS];
+};
+
+struct backlight_adj_group_init_data {
+ struct ds_dispatch *ds;
+ struct topology_mgr *tm;
+ struct hw_sequencer *hws;
+ struct adapter_service *as;
+ struct dal_context *dal_context;
+};
+
+struct backlight_adj_group *dal_backlight_adj_group_create(
+ struct backlight_adj_group_init_data *init_data);
+
+void dal_backlight_adj_group_destroy(
+ struct backlight_adj_group **backlight_adj);
+
+bool dal_backlight_adj_group_get_current_adj(
+ struct backlight_adj_group *backlight_adj,
+ struct display_path *disp_path,
+ enum adjustment_id adj_id,
+ bool allow_default,
+ uint32_t *value);
+
+enum ds_return dal_backlight_adj_group_set_backlight_adj(
+ struct backlight_adj_group *backlight_adj,
+ struct display_path *disp_path,
+ uint32_t value);
+
+enum ds_return dal_backlight_adj_group_set_backlight_optimization_adj(
+ struct backlight_adj_group *backlight_adj,
+ struct display_path *disp_path,
+ uint32_t value);
+
+
+bool dal_backlight_adj_group_add_adj_to_post_mode_set(
+ struct backlight_adj_group *backlight_adj,
+ uint32_t value,
+ struct hw_adjustment_set *set);
+
+enum ds_return dal_backlight_adj_group_set_adjustment(
+ struct backlight_adj_group *backlight_adj,
+ struct display_path *disp_path,
+ enum adjustment_id adj_id,
+ uint32_t value);
+
+#endif /*__DAL_BACKLIGHT_ADJ_GROUP_H__*/
diff --git a/drivers/gpu/drm/amd/dal/display_service/color_temperature.c b/drivers/gpu/drm/amd/dal/display_service/color_temperature.c
new file mode 100644
index 000000000000..39b92193635e
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/color_temperature.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2015 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 "color_temperature.h"
+
+
+static const struct white_point_entry white_point_table[] = {
+/*001*/ { 1000, 6499, 3474 },
+/*002*/ { 1100, 6361, 3594 },
+/*003*/ { 1200, 6226, 3703 },
+/*004*/ { 1300, 6095, 3801 },
+/*005*/ { 1400, 5966, 3887 },
+/*006*/ { 1500, 5841, 3962 },
+/*007*/ { 1600, 5720, 4025 },
+/*008*/ { 1700, 5601, 4076 },
+/*009*/ { 1800, 5486, 4118 },
+/*010*/ { 1900, 5375, 4150 },
+/*011*/ { 2000, 5267, 4173 },
+/*012*/ { 2100, 5162, 4188 },
+/*013*/ { 2200, 5062, 4196 },
+/*014*/ { 2300, 4965, 4198 },
+/*015*/ { 2400, 4872, 4194 },
+/*016*/ { 2500, 4782, 4186 },
+/*017*/ { 2600, 4696, 4173 },
+/*018*/ { 2700, 4614, 4158 },
+/*019*/ { 2800, 4535, 4139 },
+/*020*/ { 2900, 4460, 4118 },
+/*021*/ { 3000, 4388, 4095 },
+/*022*/ { 3100, 4320, 4070 },
+/*023*/ { 3200, 4254, 4044 },
+/*024*/ { 3300, 4192, 4018 },
+/*025*/ { 3400, 4132, 3990 },
+/*026*/ { 3500, 4075, 3962 },
+/*027*/ { 3600, 4021, 3934 },
+/*028*/ { 3700, 3969, 3905 },
+/*029*/ { 3800, 3919, 3877 },
+/*030*/ { 3900, 3872, 3849 },
+/*031*/ { 4000, 3827, 3820 },
+/*032*/ { 4100, 3784, 3793 },
+/*033*/ { 4200, 3743, 3765 },
+/*034*/ { 4300, 3704, 3738 },
+/*035*/ { 4400, 3666, 3711 },
+/*036*/ { 4500, 3631, 3685 },
+/*037*/ { 4600, 3596, 3659 },
+/*038*/ { 4700, 3563, 3634 },
+/*039*/ { 4800, 3532, 3609 },
+/*040*/ { 4900, 3502, 3585 },
+/*041*/ { 5000, 3473, 3561 },
+/*042*/ { 5100, 3446, 3538 },
+/*043*/ { 5200, 3419, 3516 },
+/*044*/ { 5300, 3394, 3494 },
+/*045*/ { 5400, 3369, 3472 },
+/*046*/ { 5500, 3346, 3451 },
+/*047*/ { 5600, 3323, 3431 },
+/*048*/ { 5700, 3302, 3411 },
+/*049*/ { 5800, 3281, 3392 },
+/*050*/ { 5900, 3261, 3373 },
+/*051*/ { 6000, 3242, 3355 },
+/*052*/ { 6100, 3223, 3337 },
+/*053*/ { 6200, 3205, 3319 },
+/*054*/ { 6300, 3188, 3302 },
+
+/*055*/ { 6400, 3161, 3296 },
+/*056*/ { 6500, 3127, 3290 },
+/*057*/ { 6600, 3126, 3264 },
+/*058*/ { 6700, 3125, 3238 },
+/*059*/ { 6800, 3110, 3224 },
+/*060*/ { 6900, 3097, 3209 },
+/*061*/ { 7000, 3083, 3195 },
+/*062*/ { 7100, 3070, 3181 },
+/*063*/ { 7200, 3058, 3168 },
+/*064*/ { 7300, 3045, 3154 },
+/*065*/ { 7400, 3034, 3142 },
+/*066*/ { 7500, 3022, 3129 },
+/*067*/ { 7600, 3011, 3117 },
+/*068*/ { 7700, 3000, 3105 },
+/*069*/ { 7800, 2990, 3094 },
+/*070*/ { 7900, 2980, 3082 },
+/*071*/ { 8000, 2970, 3071 },
+/*072*/ { 8100, 2961, 3061 },
+/*073*/ { 8200, 2952, 3050 },
+/*074*/ { 8300, 2943, 3040 },
+/*075*/ { 8400, 2934, 3030 },
+/*076*/ { 8500, 2926, 3020 },
+/*077*/ { 8600, 2917, 3011 },
+/*078*/ { 8700, 2910, 3001 },
+/*079*/ { 8800, 2902, 2992 },
+/*080*/ { 8900, 2894, 2983 },
+/*081*/ { 9000, 2887, 2975 },
+/*082*/ { 9100, 2880, 2966 },
+/*083*/ { 9200, 2873, 2958 },
+/*084*/ { 9300, 2866, 2950 },
+/*085*/ { 9400, 2860, 2942 },
+/*086*/ { 9500, 2853, 2934 },
+/*087*/ { 9600, 2847, 2927 },
+/*088*/ { 9700, 2841, 2919 },
+/*089*/ { 9800, 2835, 2912 },
+/*090*/ { 9900, 2829, 2905 },
+/*091*/ { 10000, 2824, 2898 },
+};
+
+bool dal_color_temperature_find_white_point(
+ int32_t request_temperature,
+ struct white_point_data *data)
+{
+ bool ret = false;
+ struct white_point_entry entry;
+
+ if (request_temperature > 0) {
+ ret =
+ dal_color_temperature_search_white_point_table(
+ request_temperature,
+ &entry);
+ if (ret == true) {
+ data->white_x = entry.dx;
+ data->white_y = entry.dy;
+ }
+ }
+ return ret;
+}
+
+bool dal_color_temperature_search_white_point_table(
+ uint32_t temp_to_find,
+ struct white_point_entry *entry)
+{
+ bool ret = false;
+ const struct white_point_entry *p;
+ uint32_t const_size;
+
+ const_size = ARRAY_SIZE(white_point_table);
+
+ for (p = white_point_table; p < &white_point_table[const_size]; p++) {
+ if (p->temperature == temp_to_find) {
+ *entry = *p;
+ ret = true;
+ break;
+ }
+ }
+ return ret;
+}
+
+bool dal_color_temperature_find_color_temperature(
+ struct white_point_data *data,
+ int32_t *temperature,
+ bool *exact_match)
+{
+ bool ret = false;
+ const struct white_point_entry *p;
+ const struct white_point_entry *next;
+ const struct white_point_entry *foundx = NULL;
+ uint32_t const_size;
+
+ const_size = ARRAY_SIZE(white_point_table);
+
+ for (p = white_point_table; p < &white_point_table[const_size]; p++) {
+ if (p->dx == data->white_x && p->dy == data->white_y) {
+ *temperature = p->temperature;
+ *exact_match = true;
+ ret = true;
+ break;
+ }
+ }
+
+ if (ret == false) {
+ for (p = white_point_table;
+ p < &white_point_table[const_size]; p++) {
+ next = p + 1;
+ if (p->dx >= data->white_x &&
+ next->dx <= data->white_x) {
+ foundx = p;
+ *exact_match = false;
+ ret = true;
+ break;
+ }
+ if (foundx != NULL)
+ *temperature = foundx->temperature;
+ }
+
+ }
+ if (ret == false) {
+ /* no such color temperature */
+ /* give default and investigate because
+ * it would be annoying for CCC */
+ *temperature = 6500;
+ ret = true;
+ }
+ return ret;
+}
diff --git a/drivers/gpu/drm/amd/dal/display_service/color_temperature.h b/drivers/gpu/drm/amd/dal/display_service/color_temperature.h
new file mode 100644
index 000000000000..03e9e49b6143
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/color_temperature.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2015 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_COLOR_TEMPERATURE_H__
+#define __DAL_COLOR_TEMPERATURE_H__
+
+/* Include */
+#include "include/adjustment_types.h"
+
+struct white_point_data {
+ uint32_t white_x;
+ uint32_t white_y;
+};
+
+struct white_point_entry {
+ int32_t temperature;
+ uint32_t dx;
+ uint32_t dy;
+};
+
+bool dal_color_temperature_find_white_point(
+ int32_t request_temperature,
+ struct white_point_data *data);
+
+bool dal_color_temperature_find_color_temperature(
+ struct white_point_data *data,
+ int32_t *temperature,
+ bool *exact_match);
+
+bool dal_color_temperature_search_white_point_table(
+ uint32_t temp_to_find,
+ struct white_point_entry *entry);
+
+#endif /*__DAL_COLOR_TEMPERATURE_H__*/
diff --git a/drivers/gpu/drm/amd/dal/display_service/display_service.c b/drivers/gpu/drm/amd/dal/display_service/display_service.c
new file mode 100644
index 000000000000..0fac5410bb09
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/display_service.c
@@ -0,0 +1,631 @@
+/*
+ * 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/display_service_interface.h"
+#include "include/topology_mgr_interface.h"
+#include "include/set_mode_interface.h"
+#include "include/hw_sequencer_interface.h"
+#include "include/link_service_interface.h"
+#include "include/adjustment_interface.h"
+#include "include/display_path_interface.h"
+
+#include "display_service.h"
+#include "ds_dispatch.h"
+#include "path_mode_set_with_data.h"
+
+struct display_service {
+ struct ds_dispatch *ds_dispatch;
+};
+
+/*
+ * Local function declaration
+ */
+/* Initialize display service */
+static bool ds_construct(
+ struct display_service *ds, const struct ds_init_data *data);
+
+/*
+ * dal_display_service_create
+ *
+ * Create display service
+ */
+struct display_service *dal_display_service_create(struct ds_init_data *data)
+{
+ struct display_service *ds;
+
+ ds = dal_alloc(sizeof(struct display_service));
+
+ if (ds == NULL)
+ return NULL;
+
+ if (ds_construct(ds, data))
+ return ds;
+
+ dal_free(ds);
+ BREAK_TO_DEBUGGER();
+
+ return NULL;
+}
+
+/*
+ * dal_display_service_destroy
+ *
+ * Destroy display service
+ */
+void dal_display_service_destroy(struct display_service **ds)
+{
+ if (!ds || !*ds) {
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+ dal_ds_dispatch_cleanup_adjustment((*ds)->ds_dispatch);
+ dal_ds_dispatch_destroy(&(*ds)->ds_dispatch);
+
+ dal_free(*ds);
+ *ds = NULL;
+}
+
+struct ds_dispatch *dal_display_service_get_adjustment_interface(
+ struct display_service *ds)
+{
+ return ds->ds_dispatch;
+}
+
+struct ds_overlay *dal_display_service_get_overlay_interface(
+ struct display_service *ds)
+{
+ /*TODO: add implementation*/
+ return NULL;
+}
+
+struct ds_dispatch *dal_display_service_get_set_mode_interface(
+ struct display_service *ds)
+{
+ if (ds == NULL)
+ return NULL;
+
+ return ds->ds_dispatch;
+}
+
+struct ds_dispatch *dal_display_service_get_reset_mode_interface(
+ struct display_service *ds)
+{
+ if (ds == NULL)
+ return NULL;
+
+ return ds->ds_dispatch;
+}
+
+struct ds_synchronization *dal_display_service_get_synchronization_interface(
+ struct display_service *ds)
+{
+ /*TODO: add implementation*/
+ return NULL;
+}
+
+enum ds_return dal_display_service_notify_v_sync_int_state(
+ struct display_service *ds,
+ uint32_t display_index,
+ bool maintain_v_sync_phase)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_display_service_target_power_control(
+ struct display_service *ds,
+ uint32_t display_index,
+ bool power_on)
+{
+ /* Handles DPMS states of all displaypaths
+ * by event and Manages the DPMS state of
+ * given DisplayPath by powerOn
+ */
+ /*TODO: Depends on AdjustmentContainer.cpp, should
+ * be uncommented once adjustmentContainer is
+ * implemented.
+ * ManageDPMSState(displayPathIndex, powerOn);*/
+
+ enum hwss_result hwss_ret = HWSS_RESULT_OK;
+ struct hw_path_mode hw_path_mode;
+ struct display_path *display_path = NULL;
+
+ if (dal_tm_is_hw_state_valid(ds->ds_dispatch->tm)) {
+ uint32_t link_cnt = 0;
+ int32_t i = 0;
+ struct active_path_data *path_data =
+ dal_pms_with_data_get_path_data_for_display_index(
+ ds->ds_dispatch->set,
+ display_index);
+
+ if (!path_data)
+ return DS_ERROR;
+
+ path_data->flags.bits.TURN_OFF_BACK_END_AND_RX =
+ power_on ? 0 : 1;
+
+ /* Create hw_path_mode for this display path*/
+ if (!dal_ds_dispatch_build_hw_path_mode_for_adjustment(
+ ds->ds_dispatch,
+ &hw_path_mode,
+ display_index,
+ NULL))
+ /* DisplayIndex requested not in
+ * currently active PathModeSet,
+ * therefore invalid parameter
+ */
+ return DS_ERROR;
+
+ /*Signal EventID_DisplayPhyAccessBegin
+ * event to allow access to Display output HW
+ */
+ /*TODO: Event eventPhyAccessBegin(
+ * EventID_DisplayPhyAccessBegin);
+ * getEM()->SendEvent(this, &eventPhyAccessBegin);
+ */
+
+ display_path = dal_tm_display_index_to_display_path(
+ ds->ds_dispatch->tm,
+ display_index);
+ link_cnt = dal_display_path_get_number_of_links(
+ display_path);
+
+ if (power_on) {
+ /* Call EnableAllowSelfRefresh
+ * when not resuming from S3 or S4. */
+ /*TODO: Remove the below
+ * comments once stutter mode
+ * is implemented.
+ if (dal_tm_get_current_power_state(
+ ds->ds_dispatch->tm) ==
+ VIDEO_POWER_ON &&
+ dal_tm_get_previous_power_state(
+ ds->ds_dispatch->tm) >
+ VIDEO_POWER_ON &&
+ dal_tm_get_previous_power_state(
+ ds->ds_dispatch->tm) <
+ VIDEO_POWER_SHUTDOWN)
+ hwss_ret =
+ dal_hw_sequencer_enable_allow_self_refresh(
+ &hw_path_mode,
+ false);
+ */
+ /* turn off DPMS light sleep - power on memories*/
+ /*TODO: Mainly used for DCE 10 & DCE11
+ * dal_tm_toggle_dpms_light_sleep(false);
+ */
+
+ /* move stream to Enabled from Power Off state*/
+ for (i = 0; i < link_cnt; i++) {
+
+ struct link_service *ls =
+ dal_display_path_get_link_config_interface(
+ display_path, i);
+
+ ASSERT_CRITICAL(ls != NULL);
+ dal_ls_power_on_stream(
+ ls,
+ display_index,
+ &hw_path_mode);
+ }
+
+
+
+ if (dal_adapter_service_is_feature_supported(
+ FEATURE_DPMS_AUDIO_ENDPOINT_CONTROL))
+ /* Enable audio device*/
+ dal_hw_sequencer_enable_azalia_audio_jack_presence(
+ ds->ds_dispatch->hwss,
+ display_path);
+ else
+ dal_hw_sequencer_mute_audio_endpoint(
+ ds->ds_dispatch->hwss,
+ display_path,
+ false);
+
+ /* move stream from Enabled to Active*/
+ for (i = 0; i < link_cnt; i++) {
+
+ struct link_service *ls =
+ dal_display_path_get_link_config_interface(
+ display_path, i);
+
+ ASSERT_CRITICAL(ls != NULL);
+
+ dal_ls_unblank_stream(
+ ls,
+ display_index,
+ &hw_path_mode);
+ }
+
+ dal_hw_sequencer_mute_audio_endpoint(
+ ds->ds_dispatch->hwss,
+ display_path,
+ false);
+
+ /* Make sure internal states are updated properly*/
+ path_data->display_state.OUTPUT_ENABLED = 1;
+ path_data->display_state.OUTPUT_BLANKED = 0;
+
+ /*
+ * Re-enable PSR if display is not in blanked state
+ */
+ if (dal_display_path_is_source_blanked(display_path) &&
+ dal_display_path_is_psr_supported(display_path))
+ dal_hw_sequencer_psr_enable(
+ ds->ds_dispatch->hwss,
+ display_path);
+
+ /* Use m_numDisplaysConnected to mark the
+ * end of wake-up/resume by setting TM's
+ * current power state to On
+ */
+ /*TODO: Depends on AdjustmentContainer.cpp, should be
+ * uncommented once AdjustmentContainer is implemented
+ * if (m_numDisplaysDPMSOn == m_numDisplaysConnected)
+ {
+ getTM()->SetCurrentPowerState(VideoPowerOn);
+ }*/
+ } else {
+ /* disable PSR*/
+ if (dal_display_path_is_psr_supported(display_path))
+ dal_hw_sequencer_psr_disable(
+ ds->ds_dispatch->hwss,
+ display_path);
+
+ /* move stream from Active to Enable state*/
+ for (i = link_cnt - 1; i >= 0; i--) {
+
+ struct link_service *ls =
+ dal_display_path_get_link_config_interface(
+ display_path, i);
+
+ ASSERT_CRITICAL(ls != NULL);
+ dal_ls_blank_stream(
+ ls,
+ display_index,
+ &hw_path_mode);
+ dal_hw_sequencer_mute_audio_endpoint(
+ ds->ds_dispatch->hwss,
+ hw_path_mode.display_path,
+ true);
+ }
+
+ /* move stream from Enable to Power Off state*/
+ for (i = link_cnt - 1; i >= 0; i--) {
+
+ struct link_service *ls =
+ dal_display_path_get_link_config_interface(
+ display_path, i);
+
+ ASSERT_CRITICAL(ls != NULL);
+
+ dal_ls_power_off_stream(
+ ls,
+ display_index,
+ &hw_path_mode);
+ }
+
+ /* blank CRTC and enable stutter
+ * mode allow_self_Refresh*/
+ /*TODO: Remove comments after implementing
+ * stutter mode
+ */
+ /* hwssRet = getHWSS()->
+ * EnableAllowSelfRefresh(
+ * &hwPathMode,
+ * true);
+
+ force SW controlled memories
+ into light sleep state
+ getTM()->ToggleDPMSLightSleep(true);
+ */
+ /* Make sure internal states
+ * are updated properly*/
+ path_data->display_state.OUTPUT_ENABLED = 0;
+ path_data->display_state.OUTPUT_BLANKED = 1;
+ }
+
+ /*TODO: PPLib Notification
+ Logical state of display might
+ change so we need to update PPlib cache
+ m_pDSDispatch->
+ NotifySingleDisplayConfig(
+ displayPathIndex,
+ true);
+
+ //Signal EventID_DisplayPhyAccessEnd
+ event to inform that Display
+ output configuration has changed
+ Event eventPhyAccessEnd(
+ EventID_DisplayPhyAccessEnd);
+ getEM()->SendEvent(
+ this, &eventPhyAccessEnd);*/
+ }
+
+ /*TODO: PPLib Notification
+ NotifyETW(DAL_NOTIFYPPLIBSCREENSTATUSCHANGE_ENTER);
+
+ notify PPLib only once -
+ when first display DPMS on or
+ last display DPMS off, pplib will program
+ NBMCU based on this.
+ if (powerOn && m_numDisplaysDPMSOn == 1)
+ {
+ getEC()->NotifyScreenStatusChange(true);
+ }
+ else if (!powerOn && m_numDisplaysDPMSOn == 0)
+ {
+ getEC()->NotifyScreenStatusChange(false);
+ //Clear m_numDisplaysConnected
+ m_numDisplaysConnected = 0;
+ }
+
+ NotifyETW(DAL_NOTIFYPPLIBSCREENSTATUSCHANGE_EXIT);
+ */
+ /* No adjustments expected be allocated
+ * no need to destroy adjustments
+ */
+ return (hwss_ret == HWSS_RESULT_OK ? DS_SUCCESS : DS_ERROR);
+}
+
+enum ds_return dal_display_service_power_down_active_hw(
+ struct display_service *ds,
+ enum dal_video_power_state state)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_display_service_mem_request_control(
+ struct display_service *ds,
+ uint32_t display_index,
+ bool blank)
+{
+ if (dal_tm_is_hw_state_valid(ds->ds_dispatch->tm)) {
+ struct display_path *display_path;
+ enum signal_type signal;
+ struct hw_path_mode mode;
+
+ if (!dal_ds_dispatch_build_hw_path_mode_for_adjustment(
+ ds->ds_dispatch, &mode, display_index, NULL))
+ return DS_ERROR;
+
+ display_path = dal_tm_create_resource_context_for_display_index(
+ ds->ds_dispatch->tm, display_index);
+
+ signal = dal_display_path_get_query_signal(
+ display_path, SINK_LINK_INDEX);
+
+ dal_tm_destroy_resource_context_for_display_path(
+ ds->ds_dispatch->tm, display_path);
+
+ if (!blank) {
+ dal_hw_sequencer_enable_memory_requests(
+ ds->ds_dispatch->hwss,
+ &mode);
+
+ if (signal == SIGNAL_TYPE_WIRELESS)
+ dal_hw_sequencer_enable_wireless_idle_detection
+ (ds->ds_dispatch->hwss, true);
+ } else {
+ dal_hw_sequencer_disable_memory_requests(
+ ds->ds_dispatch->hwss,
+ &mode);
+ if (signal == SIGNAL_TYPE_WIRELESS)
+ dal_hw_sequencer_enable_wireless_idle_detection
+ (ds->ds_dispatch->hwss, false);
+ }
+ }
+
+ return DS_SUCCESS;
+}
+
+enum ds_return dal_display_service_set_multimedia_pass_through_mode(
+ struct display_service *ds,
+ uint32_t display_index,
+ bool passThrough)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_display_service_set_palette(
+ struct display_service *ds,
+ uint32_t display_index,
+ const struct ds_devclut *palette,
+ const uint32_t start,
+ const uint32_t length)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_display_service_apply_pix_clk_range(
+ struct display_service *ds,
+ uint32_t display_index,
+ struct pixel_clock_safe_range *range)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_display_service_get_safe_pix_clk(
+ struct display_service *ds,
+ uint32_t display_index,
+ uint32_t *pix_clk_khz)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_display_service_apply_refreshrate_adjustment(
+ struct display_service *ds,
+ uint32_t display_index,
+ enum ds_refreshrate_adjust_action action,
+ struct ds_refreshrate *refreshrate)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_display_service_pre_ddc(
+ struct display_service *ds,
+ uint32_t display_index)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_display_service_post_ddc(
+ struct display_service *ds,
+ uint32_t display_index)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_display_service_backlight_control(
+ struct display_service *ds,
+ uint32_t display_index,
+ bool enable)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_display_service_get_backlight_user_level(
+ struct display_service *ds,
+ uint32_t display_index,
+ uint32_t *level)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_display_service_get_backlight_effective_level(
+ struct display_service *ds,
+ uint32_t display_index,
+ uint32_t *level)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_display_service_enable_hpd(
+ struct display_service *ds,
+ uint32_t display_index)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_display_service_disable_hpd(
+ struct display_service *ds,
+ uint32_t display_index)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_display_service_get_min_mem_channels(
+ struct display_service *ds,
+ const struct path_mode_set *path_mode_set,
+ uint32_t mem_channels_num,
+ uint32_t *min_mem_channels_num)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_display_service_enable_advanced_request(
+ struct display_service *ds,
+ bool enable)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+/*Audio related*/
+
+enum ds_return dal_display_service_enable_audio_endpoint(
+ struct display_service *ds,
+ uint32_t display_index,
+ bool enable)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_display_service_mute_audio_endpoint(
+ struct display_service *ds,
+ uint32_t display_index,
+ bool mute)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+bool dal_display_service_calc_view_port_for_wide_display(
+ struct display_service *ds,
+ uint32_t display_index,
+ const struct ds_view_port *set_view_port,
+ struct ds_get_view_port *get_view_port)
+{
+ /*TODO: add implementation*/
+ return false;
+}
+
+/*
+ * Local function definition
+ */
+
+/*
+ * ds_construct
+ *
+ * Initialize display service
+ */
+static bool ds_construct(
+ struct display_service *ds, const struct ds_init_data *data)
+{
+ struct ds_dispatch_init_data dispatch_data;
+
+ if (data == NULL)
+ return false;
+
+ dispatch_data.dal_context = data->dal_context;
+ dispatch_data.as = data->as;
+ dispatch_data.hwss = data->hwss;
+ dispatch_data.tm = data->tm;
+ dispatch_data.ts = data->ts;
+
+ ds->ds_dispatch = dal_ds_dispatch_create(&dispatch_data);
+
+ if (ds->ds_dispatch == NULL)
+ return false;
+
+ return true;
+}
diff --git a/drivers/gpu/drm/amd/dal/display_service/display_service.h b/drivers/gpu/drm/amd/dal/display_service/display_service.h
new file mode 100644
index 000000000000..7b0596eb37b7
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/display_service.h
@@ -0,0 +1,30 @@
+/*
+ * 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_SERVICE_H__
+#define __DAL_DISPLAY_SERVICE_H__
+
+
+#endif
diff --git a/drivers/gpu/drm/amd/dal/display_service/ds_calculation.c b/drivers/gpu/drm/amd/dal/display_service/ds_calculation.c
new file mode 100644
index 000000000000..cc26248c1efc
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/ds_calculation.c
@@ -0,0 +1,288 @@
+
+/*
+ * 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 */
+#include "dal_services.h"
+
+/*#include "include/set_mode_interface.h"
+#include "include/hw_path_mode_set_interface.h"
+#include "include/topology_mgr_interface.h"
+#include "include/dcs_interface.h"
+#include "include/link_service_interface.h"*/
+#include "include/display_path_interface.h"
+#include "include/display_service_types.h"
+#include "include/hw_sequencer_types.h"
+#include "include/timing_service_types.h"
+#include "include/dcs_types.h"
+
+#include "ds_calculation.h"
+
+/*
+ * Public function definition
+ */
+
+/* Adjust timing to the timing limits. */
+void dal_ds_calculation_tuneup_timing(
+ struct hw_crtc_timing *timing,
+ const struct timing_limits *timing_limits)
+{
+ uint32_t cur_pixel_clock;
+ uint32_t new_pixel_clock;
+ uint32_t new_h_total;
+
+ if ((timing_limits == NULL) ||
+ (timing == NULL) ||
+ (timing->h_total == 0) ||
+ (timing->v_total == 0)) {
+ return;
+ }
+
+ /* Perform all calculations in DS internal units [kHz] */
+ cur_pixel_clock = timing->pixel_clock;
+ new_h_total = timing->h_total;
+
+ /* Set pixel clock in the middle of the range.
+ * Upper layer should provide a valid range. */
+ new_pixel_clock =
+ (timing_limits->max_pixel_clock_in_khz +
+ timing_limits->min_pixel_clock_in_khz) /
+ 2;
+
+ if ((new_pixel_clock > 0) &&
+ (new_pixel_clock != cur_pixel_clock)) {
+ uint32_t v_h_total = timing->h_total * timing->v_total;
+ uint32_t refresh_rate =
+ ((timing->pixel_clock * 1000) + (v_h_total / 2)) /
+ v_h_total;
+
+ /* Pixel clock adjusted to fit in the range; adjust HTOTAL to
+ * preserve refresh rate.
+ *
+ * SS = Sync Start
+ * SE = Sync End
+ * SW = Sync Width
+ * HA = Horizontal Active
+ * HT = Horizontal Total
+ * HBS = Horizontal Blank Start
+ * HBE = Horizontal Blank End
+ * FP = FrontPorch (affected by changing Horizontal Total)
+ *
+ * SS. .SE
+ * ______ ________________ ______
+ * ___| |______|xxxxxxxxxxxxxxxx|______| |___
+ * | | | | |
+ * |<-SW->| |<------HA------>| |
+ * | | | |
+ * |<-----------------HT---------------->|
+ * | | | |
+ * |--------------HBS------------>| |
+ * |-----HBE---->| | |
+ * | |
+ * |<-FP->|
+ * 32 164 2084 2184
+ *
+ * Assuming there is no pixel repetition, register programming
+ * will look like this:
+ *
+ * CRTC_H_TOTAL = HTotal
+ * CRTC_H_SYNC_X_START = 0
+ * CRTC_H_SYNC_X_END = HSyncWidth
+ * CRTC_H_BANK_START = HTotal - (HSyncStart - HActive)
+ * CRTC_H_BANK_END = HTotal - HSyncStart
+ *
+ * pixelClock = HTotal * VTotal * refRate =>
+ * HTotal = pixelClock / VTotal / refRate
+ *
+ * newFrontPorch = newHTtotal - blankStart =
+ * (newPixelClock/VTotal/refRate) - blankStart */
+
+ int32_t cur_front_porch =
+ timing->h_sync_start - timing->h_addressable;
+ int32_t blank_start =
+ timing->h_total - cur_front_porch;
+ int32_t new_front_porch =
+ (new_pixel_clock *
+ PIXEL_CLOCK_MULTIPLIER /
+ timing->v_total /
+ refresh_rate) -
+ blank_start;
+
+ /* New HTOTAL differs from current one by front porch
+ * difference */
+ new_h_total += new_front_porch - cur_front_porch;
+ timing->pixel_clock = new_pixel_clock;
+ timing->h_total = new_h_total;
+ }
+}
+
+/* Setup ranged timing parameters for features such as DRR or PSR. */
+void dal_ds_calculation_setup_ranged_timing(
+ struct hw_crtc_timing *timing,
+ struct display_path *display_path,
+ struct ranged_timing_preference_flags flags)
+{
+ uint64_t fps_in_micro_hz = 0;
+ bool drr_supported = false;
+ bool psr_supported = false;
+ bool vce_supported = false;
+ struct drr_config drr_config;
+ uint32_t v_h_total;
+ struct hw_ranged_timing *rt;
+
+ if ((display_path == NULL) || (timing == NULL))
+ return;
+
+ /* Temporary pointer to ranged timing we want to build */
+ rt = &timing->ranged_timing;
+
+ /* Initialize flags to program both static screen event triggers and
+ * dynamic refresh rate.
+ * Originally, the purpose of these flags is to prevent DRR from being
+ * enabled if PSR was supported. But in current implementation, PSR may
+ * be used in static screen, while DRR can still be enabled during non-
+ * static state. Because of this, we always need prepare ranged timing
+ * for both features. When we do actual programming, we may set flags
+ * to enable the feature we actually want at the current state. */
+ rt->control.program_static_screen_mask = false;
+ rt->control.program_dynamic_refresh_rate = false;
+ rt->control.force_disable_drr = false;
+
+ /* 1. Check for features that require Static Screen Detection */
+ v_h_total = timing->h_total * timing->v_total;
+ if (v_h_total != 0) {
+ fps_in_micro_hz = timing->pixel_clock * 1000;
+ fps_in_micro_hz *= 1000000;
+ fps_in_micro_hz = div_u64(fps_in_micro_hz, v_h_total);
+ }
+
+ dal_display_path_get_drr_config(display_path, &drr_config);
+
+ if (dal_display_path_is_psr_supported(display_path)) {
+ /* Check if PSR is supported. PSR requires static screen
+ * detection enabled in HW. */
+ psr_supported = true;
+
+ /* If PSR is enabled, DRR should be force disabled
+ * unless we override later by forced flags. */
+ rt->control.force_disable_drr = true;
+ } else if (dal_display_path_get_config_signal(
+ display_path, SINK_LINK_INDEX) ==
+ SIGNAL_TYPE_WIRELESS) {
+ /* Check if this display is a Wireless Display by checking
+ * the sink signal type. If this is a Wireless Display, static
+ * screen detection may be enabled for power saving. */
+ vce_supported = true;
+ } else if (dal_display_path_is_drr_supported(display_path)) {
+ /* The check for DRR supported returns true means it satisfied:
+ * 1. EDID reported DRR capability and Stream supports DRR or
+ * 2. Forced capability through runtime parameter or
+ * 3. Forced capability through VBIOS */
+ drr_supported = true;
+ }
+
+ /* 2. Apply some override flags */
+ if (flags.bits.force_disable_drr == 1) {
+ /* Setup ranged timing parameters to force disable DRR.
+ * This is typically set if PSR is being enabled and we want
+ * to force disable DRR. */
+ rt->control.force_disable_drr = true;
+ } else if (flags.bits.prefer_enable_drr == 1) {
+ /* Preference flag to enable DRR with higher priority. For
+ * static screen power saving use case, DRR is usually not
+ * enabled if PSR is also supported in the system. But in this
+ * case it may be OS telling us to disable power feature for
+ * screen active. Then we want to use DRR for matching render
+ * and refresh rates. */
+ rt->control.force_disable_drr = false;
+ }
+
+ /* 3. If any feature is supported on the display, enable static screen
+ * detection and prepare ranged timing. */
+ if (drr_supported || psr_supported || vce_supported) {
+ struct static_screen_events ss_events;
+
+ rt->control.program_static_screen_mask = true;
+
+ /* Initialize to the VTOTAL value. This means refresh rate will
+ * be constant. */
+ rt->vertical_total_min = timing->v_total;
+ rt->vertical_total_max = timing->v_total;
+
+ /* Prevent divide by zero. We always want to build DRR settings
+ * if possible, even if not for static screen purpose. It could
+ * still be used for 48 Hz feature. */
+ if (drr_config.min_fps_in_microhz != 0) {
+ timing->ranged_timing.control.program_dynamic_refresh_rate
+ = true;
+
+ /* If DRR is supported, update DRR parameters with min
+ * and max VTOTAL values to define the refresh rate
+ * range. */
+ rt->vertical_total_min = timing->v_total;
+ rt->vertical_total_max =
+ div_u64((timing->v_total * fps_in_micro_hz),
+ drr_config.min_fps_in_microhz);
+
+ rt->control.force_lock_on_event =
+ drr_config.force_lock_on_event;
+ rt->control.lock_to_master_vsync =
+ drr_config.lock_to_master_vsync;
+ }
+
+ dal_display_path_get_static_screen_triggers(
+ display_path, &ss_events);
+
+ rt->control.event_mask.u_all = 0;
+ rt->control.event_mask.bits.FRAME_START =
+ ss_events.bits.FRAME_START;
+ rt->control.event_mask.bits.CURSOR_MOVE =
+ ss_events.bits.CURSOR_MOVE;
+ rt->control.event_mask.bits.MEM_WRITE =
+ ss_events.bits.MEM_WRITE;
+ rt->control.event_mask.bits.MEM_REGION0_WRITE =
+ ss_events.bits.MEM_REGION0_WRITE;
+ rt->control.event_mask.bits.MEM_REGION1_WRITE =
+ ss_events.bits.MEM_REGION1_WRITE;
+ rt->control.event_mask.bits.MEM_REGION2_WRITE =
+ ss_events.bits.MEM_REGION2_WRITE;
+ rt->control.event_mask.bits.MEM_REGION3_WRITE =
+ ss_events.bits.MEM_REGION3_WRITE;
+ rt->control.event_mask.bits.GFX_UPDATE =
+ ss_events.bits.GFX_UPDATE;
+ rt->control.event_mask.bits.INVALIDATE_FBC_SURFACE =
+ ss_events.bits.INVALIDATE_FBC_SURFACE;
+ rt->control.event_mask.bits.REG_PENDING_UPDATE =
+ ss_events.bits.REG_PENDING_UPDATE;
+ rt->control.event_mask.bits.CRTC_TRIG_A =
+ ss_events.bits.CRTC_TRIG_A;
+ rt->control.event_mask.bits.CRTC_TRIG_B =
+ ss_events.bits.CRTC_TRIG_B;
+ rt->control.event_mask.bits.READBACK_NOMINAL_VERTICAL =
+ ss_events.bits.READBACK_NOMINAL_VERTICAL;
+ rt->control.event_mask.bits.READBACK_DYNAMIC_VERTICAL =
+ ss_events.bits.READBACK_DYNAMIC_VERTICAL;
+ }
+}
diff --git a/drivers/gpu/drm/amd/dal/display_service/ds_calculation.h b/drivers/gpu/drm/amd/dal/display_service/ds_calculation.h
new file mode 100644
index 000000000000..5d3b4845ee69
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/ds_calculation.h
@@ -0,0 +1,48 @@
+/*
+ * 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_DS_CALCULATION_H__
+#define __DAL_DS_CALCULATION_H__
+
+/* Includes */
+/* None */
+
+struct hw_crtc_timing;
+struct timing_limits;
+struct ranged_timing_preference_flags;
+struct display_path;
+
+/* Adjust timing to the timing limits. */
+void dal_ds_calculation_tuneup_timing(
+ struct hw_crtc_timing *timing,
+ const struct timing_limits *timing_limits);
+
+/* Setup ranged timing parameters for features such as DRR or PSR. */
+void dal_ds_calculation_setup_ranged_timing(
+ struct hw_crtc_timing *timing,
+ struct display_path *display_path,
+ struct ranged_timing_preference_flags flags);
+
+#endif /* __DAL_DS_CALCULATION_H__ */
diff --git a/drivers/gpu/drm/amd/dal/display_service/ds_dispatch.h b/drivers/gpu/drm/amd/dal/display_service/ds_dispatch.h
new file mode 100644
index 000000000000..4cf6b5e8e59e
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/ds_dispatch.h
@@ -0,0 +1,137 @@
+/*
+ * 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_DS_DISPATCH_H__
+#define __DAL_DS_DISPATCH_H__
+
+#include "include/adjustment_types.h"
+
+#include "path_mode_set_with_data.h"
+
+#define MAX_NUM_SUPPORT_SIGNAL (DS_SIGNAL_TYPE_END - DS_SIGNAL_TYPE_BEGIN + 1)
+#define REGAMMA_COEFF_A0 31308
+#define REGAMMA_COEFF_A1 12920
+#define REGAMMA_COEFF_A2 55
+#define REGAMMA_COEFF_A3 55
+#define REGAMMA_COEFF_GAMMA 2400
+
+/* TODO: remove this once defined */
+struct hw_get_viewport_x_adjustments;
+struct topology_mgr;
+struct hw_sequencer;
+struct adapter_service;
+struct hw_path_mode;
+
+enum ds_signal_type {
+ DS_SIGNAL_TYPE_CRT = 0, /* the first */
+ DS_SIGNAL_TYPE_DISCRETEVGA,
+ DS_SIGNAL_TYPE_DFP,
+ DS_SIGNAL_TYPE_LVDS,
+ DS_SIGNAL_TYPE_HDMI,
+ DS_SIGNAL_TYPE_DP,
+ DS_SIGNAL_TYPE_EDP,
+ DS_SIGNAL_TYPE_CF,
+ DS_SIGNAL_TYPE_WIRELESS, /* the last */
+ DS_SIGNAL_TYPE_UNKNOWN,
+
+ DS_SIGNAL_TYPE_BEGIN = DS_SIGNAL_TYPE_CRT,
+ DS_SIGNAL_TYPE_END = DS_SIGNAL_TYPE_WIRELESS
+};
+/* Purpose to build the path set for */
+enum build_path_set_reason {
+ BUILD_PATH_SET_REASON_SET_MODE = 0,
+ BUILD_PATH_SET_REASON_WATERMARKS,
+ BUILD_PATH_SET_REASON_VALIDATE,
+ BUILD_PATH_SET_REASON_SET_ADJUSTMENT,
+ BUILD_PATH_SET_REASON_GET_ACTIVE_PATHS,
+ BUILD_PATH_SET_REASON_FALLBACK_UNDERSCAN
+};
+
+struct adj_global_info {
+ enum adjustment_id adj_id;
+ enum adjustment_data_type adj_data_type;
+ union adjustment_property adj_prop;
+ bool display_is_supported[MAX_NUM_SUPPORT_SIGNAL];
+};
+
+/* Display service dispatch init data */
+struct ds_dispatch_init_data {
+ struct dal_context *dal_context;
+ struct hw_sequencer *hwss;
+ struct topology_mgr *tm;
+ struct adapter_service *as;
+ struct timing_service *ts;
+};
+
+/* Display service dispatch */
+struct ds_dispatch {
+ struct dal_context *dal_context;
+ struct path_mode_set_with_data *set;
+ struct topology_mgr *tm;
+ struct hw_sequencer *hwss;
+ struct adapter_service *as;
+ struct timing_service *ts;
+ struct adj_container **applicable_adj;
+ struct adjustment_parent_api *default_adjustments;
+
+ /* Temporary storage for Path Mode Set validation. */
+ struct path_mode path_modes[MAX_COFUNC_PATH];
+ uint32_t disp_path_num;
+ struct backlight_adj_group *backlight_adj;
+ struct single_adj_group *single_adj;
+ struct grph_colors_group *grph_colors_adj;
+ struct grph_gamma_lut_group *grph_gamma_adj;
+};
+
+
+/*
+ * DS dispatch functions
+ */
+
+/* Create DS dispatch */
+struct ds_dispatch *dal_ds_dispatch_create(
+ const struct ds_dispatch_init_data *data);
+
+/* Destroy DS dispatch */
+void dal_ds_dispatch_destroy(struct ds_dispatch **ds_dispatch);
+
+/* Set up info frames */
+void dal_ds_dispatch_setup_info_frame(
+ struct ds_dispatch *ds_dispatch,
+ const struct path_mode *mode,
+ struct hw_path_mode *hw_mode);
+
+/* Check if gamut needs reprogramming */
+bool dal_ds_dispatch_is_gamut_change_required(
+ struct ds_dispatch *ds_dispatch,
+ enum pixel_encoding pixel_encoding,
+ enum pixel_format pixel_format,
+ uint32_t disp_index);
+
+/* Return active path modes */
+struct path_mode_set_with_data *dal_ds_dispatch_get_active_pms_with_data(
+ struct ds_dispatch *ds_dispatch);
+
+#endif /* __DAL_DS_DISPATCH_H__ */
diff --git a/drivers/gpu/drm/amd/dal/display_service/ds_dispatch_adjustment.c b/drivers/gpu/drm/amd/dal/display_service/ds_dispatch_adjustment.c
new file mode 100644
index 000000000000..6210302e74ce
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/ds_dispatch_adjustment.c
@@ -0,0 +1,1128 @@
+/*
+ * 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/adjustment_interface.h"
+#include "include/display_path_interface.h"
+#include "include/signal_types.h"
+#include "include/dcs_interface.h"
+#include "include/topology_mgr_interface.h"
+#include "include/display_service_interface.h"
+#include "include/set_mode_interface.h"
+#include "include/logger_interface.h"
+#include "include/fixed31_32.h"
+
+#include "ds_dispatch.h"
+#include "adjustment_container.h"
+#include "scaler_adj_group.h"
+#include "adjustment_api.h"
+#include "backlight_adj_group.h"
+#include "single_adj_group.h"
+#include "grph_colors_group.h"
+#include "gamut_space.h"
+#include "gamma_lut.h"
+#include "path_mode_set_with_data.h"
+
+#define NOT_IMPLEMENTED() DAL_LOGGER_NOT_IMPL( \
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE, "Display Service:%s\n", __func__)
+
+/* NOTE make sure to update CURRENT_ADJUSTMENT_NUM when updating this array */
+static const struct adj_global_info adj_global_info_array[CURRENT_ADJUSTMENT_NUM] = {
+ { ADJ_ID_SATURATION, ADJ_RANGED, { 0x140 }, { 1, 1, 1, 1, 1, 1, 1, 0, 1 } },
+ { ADJ_ID_BIT_DEPTH_REDUCTION, ADJ_RANGED, { 0x14A }, { 1, 1, 1, 1, 1, 1, 1, 0, 0 } },
+ { ADJ_ID_UNDERSCAN, ADJ_RANGED, { 0x145 }, { 0, 0, 1, 1, 1, 1, 1, 0, 1 } },
+ { ADJ_ID_UNDERSCAN_TYPE, ADJ_RANGED, { 0x101 }, { 0, 0, 1, 0, 1, 0, 0, 0, 1 } },
+ { ADJ_ID_BACKLIGHT, ADJ_RANGED, { 0x1a0 }, { 1, 1, 1, 1, 1, 1, 1, 0, 0 } },
+ { ADJ_ID_CONTRAST, ADJ_RANGED, { 0x160 }, { 1, 1, 1, 1, 1, 1, 1, 0, 1 } },
+ { ADJ_ID_BRIGHTNESS, ADJ_RANGED, { 0x140 }, { 1, 1, 1, 1, 1, 1, 1, 0, 1 } },
+ { ADJ_ID_HUE, ADJ_RANGED, { 0x140 }, { 1, 1, 1, 1, 1, 1, 1, 0, 1 } },
+ { ADJ_ID_TEMPERATURE, ADJ_RANGED, { 0x140 }, { 1, 1, 1, 1, 1, 1, 1, 0, 1 } },
+ { ADJ_ID_TEMPERATURE_SOURCE, ADJ_RANGED, { 0x142 }, { 1, 1, 1, 1, 0, 1, 1, 0, 1 } },
+ { ADJ_ID_NOMINAL_RANGE_RGB_LIMITED, ADJ_RANGED, { 0x141 }, { 1, 1, 1, 1, 1, 1, 1, 0, 1 } },
+ { ADJ_ID_GAMMA_RAMP, ADJ_LUT, { 0x108 }, { 1, 1, 1, 1, 1, 1, 1, 1, 1 } }
+};
+
+static void build_adj_container_for_path(struct ds_dispatch *ds,
+ struct display_path *display_path);
+
+static enum ds_signal_type get_ds_signal_from_display_path(
+ struct ds_dispatch *ds,
+ struct display_path *display_path,
+ uint32_t idx);
+
+/*get info from global table adj_global_info_array*/
+static enum ds_return get_adj_type(
+ struct ds_dispatch *ds,
+ enum adjustment_id adj_id,
+ enum adjustment_data_type *type)
+{
+ uint32_t i = 0;
+
+ if (adj_id < ADJ_ID_BEGIN || ADJ_ID_END < adj_id)
+ return DS_ERROR;
+ for (i = 0; i < CURRENT_ADJUSTMENT_NUM; i++) {
+ if (adj_global_info_array[i].adj_id == adj_id) {
+ *type = adj_global_info_array[i].adj_data_type;
+ return DS_SUCCESS;
+ }
+ }
+ return DS_ERROR;
+}
+
+static enum ds_return get_adj_info_from_defaults(
+ struct ds_dispatch *ds,
+ uint32_t disp_index,
+ struct display_path *path,
+ enum adjustment_id adjust_id,
+ struct adjustment_info *adj_info)
+{
+ struct adjustment_api *api = NULL;
+ enum signal_type signal;
+ union cea_video_capability_data_block video_cap = { {0} };
+ struct dcs *dcs = dal_display_path_get_dcs(path);
+
+ dal_dcs_get_cea_video_capability_data_block(dcs, &video_cap);
+ signal = dal_display_path_get_query_signal(path, SINK_LINK_INDEX);
+
+ api = dal_adj_parent_api_what_is_the_target_obj(
+ ds->default_adjustments,
+ signal);
+ if (!api)
+ return DS_ERROR;
+ get_adj_type(
+ ds,
+ adjust_id,
+ &adj_info->adj_data_type);
+
+ if (adj_info->adj_data_type == ADJ_RANGED) {
+ /*default value from table*/
+ if (!dal_adj_api_get_range_adj_data(
+ api, adjust_id, adj_info))
+ return DS_ERROR;
+ /*then override it by signal types and other requests*/
+ if (adjust_id == ADJ_ID_UNDERSCAN) {
+ if (signal == SIGNAL_TYPE_DVI_SINGLE_LINK ||
+ signal == SIGNAL_TYPE_DVI_SINGLE_LINK1 ||
+ signal == SIGNAL_TYPE_DVI_DUAL_LINK ||
+ signal == SIGNAL_TYPE_HDMI_TYPE_A ||
+ signal == SIGNAL_TYPE_WIRELESS) {
+ /*reviewers:this parts i changed a little bit
+ * compare with dal2*/
+ /*we set 0 underscan for non-HDMI or S_CE1 is
+ * 1,S_CE1 indicates monitor will underscan
+ * automaticlly*/
+ if (video_cap.bits.S_CE1 || signal !=
+ SIGNAL_TYPE_HDMI_TYPE_A)
+ adj_info->adj_data.ranged.def = 0;
+ }
+ }
+
+ }
+ return DS_SUCCESS;
+}
+
+static bool is_underscan_supported(
+ struct ds_dispatch *ds,
+ struct display_path *path,
+ enum dcs_edid_connector_type connector_type,
+ enum ds_signal_type ds_signal
+ )
+{
+ bool supported = true;
+ /* This call will check if underscan requirements are met.
+ Currently, this is checking to see if the display engine
+ clock is high enough to support underscan.*/
+ if (!dal_adapter_service_is_meet_underscan_req(ds->as))
+ supported = false;
+ /* Checks if underscan is for HDMI only */
+ else if (dal_adapter_service_underscan_for_hdmi_only(ds->as)) {
+ connector_type = dal_dcs_get_connector_type(
+ dal_display_path_get_dcs(path));
+
+ if (!((connector_type == EDID_CONNECTOR_HDMIA) ||
+ (dal_adapter_service_is_feature_supported(
+ FEATURE_INSTANT_UP_SCALE_DOWN_SCALE) &&
+ (ds_signal == DS_SIGNAL_TYPE_EDP))))
+ supported = false;
+
+ } else if (!dal_adapter_service_is_feature_supported(
+ FEATURE_INSTANT_UP_SCALE_DOWN_SCALE)) {
+ if (ds_signal == DS_SIGNAL_TYPE_EDP)
+ supported = false;
+ } else
+ supported = true;
+ return supported;
+}
+
+static bool is_adjustment_supported(
+ struct ds_dispatch *ds,
+ struct display_path *path,
+ enum adjustment_id adjust_id)
+{
+ bool supported = true;
+ uint32_t display_index;
+ uint32_t index = 0;
+ enum ds_signal_type ds_signal;
+ enum dcs_edid_connector_type connector_type;
+
+ if (!path) {
+ dal_logger_write(ds->dal_context->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "display path is NULL");
+ return false;
+ }
+ display_index = dal_tm_display_path_to_display_index(ds->tm, path);
+ ds_signal = get_ds_signal_from_display_path(ds, path, display_index);
+ connector_type =
+ dal_dcs_get_connector_type(
+ dal_display_path_get_dcs(path));
+ if (ds_signal == DS_SIGNAL_TYPE_UNKNOWN) {
+ dal_logger_write(ds->dal_context->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "DS_SIGNAL_TYPE_UNKNOWN");
+ return false;
+ }
+ for (index = 0; index < CURRENT_ADJUSTMENT_NUM; index++) {
+ if (adjust_id == adj_global_info_array[index].adj_id) {
+ if (false == adj_global_info_array[index].
+ display_is_supported[ds_signal])
+ return false;
+ else {
+ if ((adjust_id == ADJ_ID_UNDERSCAN) ||
+ (adjust_id == ADJ_ID_UNDERSCAN_TYPE))
+ supported =
+ is_underscan_supported(
+ ds,
+ path,
+ connector_type,
+ ds_signal);
+ break;
+ }
+ }
+ }
+ return supported;
+}
+
+static enum ds_return get_adjustment_info(
+ struct ds_dispatch *ds,
+ struct display_path *disp_path,
+ enum adjustment_id adjust_id,
+ bool fallback_to_default,
+ struct adjustment_info *adj_info)
+{
+ uint32_t display_index =
+ dal_display_path_get_display_index(disp_path);
+ struct adj_container *adj_container =
+ dal_ds_dispatch_get_adj_container_for_path(ds, display_index);
+ const struct adjustment_info *cont_info =
+ dal_adj_info_set_get_adj_info(
+ &adj_container->adj_info_set, adjust_id);
+
+ if (disp_path == NULL || adj_info == NULL ||
+ !is_adjustment_supported(ds, disp_path, adjust_id))
+ return DS_ERROR;
+
+ if (!adj_container)
+ return DS_ERROR;
+
+ if (cont_info != NULL)
+ *adj_info = *cont_info;
+ else if (fallback_to_default)
+ return get_adj_info_from_defaults(
+ ds,
+ display_index,
+ disp_path,
+ adjust_id,
+ adj_info);
+ else
+ return DS_ERROR;
+
+ return DS_SUCCESS;
+}
+
+enum ds_return dal_ds_dispatch_get_adjustment_info(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ enum adjustment_id adjust_id,
+ struct adjustment_info *adj_info)
+{
+ struct display_path *display_path =
+ dal_tm_display_index_to_display_path(
+ ds->tm, display_index);
+ return get_adjustment_info(
+ ds,
+ display_path,
+ adjust_id,
+ true,
+ adj_info);
+}
+
+static enum ds_return get_adj_property(
+ struct ds_dispatch *ds,
+ uint32_t disp_index,
+ enum adjustment_id adjust_id,
+ union adjustment_property *adj_property)
+{
+ enum ds_return result = DS_ERROR;
+ uint32_t i = 0;
+
+ if (disp_index >= dal_tm_get_num_display_paths(ds->tm, false))
+ return DS_ERROR;
+ for (i = 0; i < CURRENT_ADJUSTMENT_NUM; i++) {
+ if (adj_global_info_array[i].adj_id == adjust_id) {
+ *adj_property = adj_global_info_array[i].adj_prop;
+ result = DS_SUCCESS;
+ break;
+ }
+ }
+ return result;
+}
+/* no used for now
+static void update_adj_container_use_edid(
+ struct ds_dispatch *ds,
+ struct display_path *display_path)
+{
+
+}*/
+
+static void build_gamut_adj_for_path(
+ struct ds_dispatch *ds,
+ uint32_t disp_index,
+ struct adj_container *adj_container,
+ struct display_path *display_path)
+{
+ struct gamut_data gamut_source_grph;
+ struct gamut_data gamut_destination;
+ struct ds_regamma_lut *regamma = NULL;
+
+ dal_memset(&gamut_source_grph, 0, sizeof(gamut_source_grph));
+ dal_memset(&gamut_destination, 0, sizeof(gamut_destination));
+
+ /* Gamut source grph */
+ dal_gamut_space_setup_default_gamut(
+ ADJ_ID_GAMUT_SOURCE_GRPH,
+ &gamut_source_grph,
+ true,
+ true);
+ dal_adj_container_update_gamut(
+ adj_container,
+ ADJ_ID_GAMUT_SOURCE_GRPH,
+ &gamut_source_grph);
+
+ /* Gamut Destination */
+ dal_gamut_space_setup_default_gamut(
+ ADJ_ID_GAMUT_DESTINATION,
+ &gamut_destination,
+ true,
+ true);
+ dal_adj_container_update_gamut(
+ adj_container,
+ ADJ_ID_GAMUT_DESTINATION,
+ &gamut_destination);
+
+ regamma = dal_alloc(sizeof(*regamma));
+ if (!dal_gamut_space_setup_predefined_regamma_coefficients(
+ &gamut_destination, regamma))
+ dal_ds_dispatch_setup_default_regamma(
+ ds, regamma);
+
+ dal_adj_container_set_regamma(
+ adj_container,
+ regamma);
+
+ dal_free(regamma);
+ regamma = NULL;
+
+}
+
+void dal_ds_dispatch_setup_default_regamma(
+ struct ds_dispatch *ds,
+ struct ds_regamma_lut *regamma)
+{
+ uint32_t i;
+
+ regamma->flags.u32all = 0;
+ regamma->flags.bits.COEFF_FROM_USER = 1;
+
+ for (i = 0 ; i < COEFF_RANGE ; i++) {
+ regamma->coeff.coeff_a0[i] = REGAMMA_COEFF_A0;
+ regamma->coeff.coeff_a1[i] = REGAMMA_COEFF_A1;
+ regamma->coeff.coeff_a2[i] = REGAMMA_COEFF_A2;
+ regamma->coeff.coeff_a3[i] = REGAMMA_COEFF_A3;
+ regamma->coeff.gamma[i] = REGAMMA_COEFF_GAMMA;
+ }
+
+}
+
+enum ds_return dal_ds_dispatch_get_adjustment_current_value(
+ struct ds_dispatch *ds,
+ struct adj_container *container,
+ struct adjustment_info *info,
+ enum adjustment_id id,
+ bool fall_back_to_default)
+{
+ if (info)
+ if (info->adj_data_type == ADJ_RANGED)
+ info->adj_data.ranged.cur = info->adj_data.ranged.def;
+ if (id == ADJ_ID_UNDERSCAN || id == ADJ_ID_UNDERSCAN_TYPE)
+ if (container &&
+ dal_adj_container_get_default_underscan_allow(
+ container))
+ info->adj_data.ranged.cur = 0;
+ return DS_SUCCESS;
+}
+
+enum ds_return dal_ds_dispatch_get_adjustment_value(
+ struct ds_dispatch *ds,
+ struct display_path *disp_path,
+ enum adjustment_id adj_id,
+ bool fall_back_to_default,
+ int32_t *value)
+{
+ uint32_t display_index;
+ struct adj_container *adj_container;
+ struct adjustment_info adj_info;
+
+ if (!disp_path)
+ return DS_ERROR;
+
+ if (!is_adjustment_supported(ds, disp_path, adj_id))
+ return DS_ERROR;
+
+ display_index = dal_display_path_get_display_index(
+ disp_path);
+ adj_container = dal_ds_dispatch_get_adj_container_for_path(
+ ds, display_index);
+
+ if (DS_SUCCESS != get_adjustment_info(ds,
+ disp_path, adj_id,
+ fall_back_to_default, &adj_info))
+ return DS_ERROR;
+
+ *value = adj_info.adj_data.ranged.cur;
+
+ if (adj_id == ADJ_ID_UNDERSCAN || adj_id == ADJ_ID_UNDERSCAN_TYPE)
+ if (adj_container &&
+ dal_adj_container_get_default_underscan_allow(
+ adj_container))
+ *value = 0;
+ if (adj_info.adj_data_type == ADJ_RANGED)
+ adj_info.adj_data.ranged.cur = *value;
+ else if (adj_info.adj_data_type == ADJ_BITVECTOR)
+ adj_info.adj_data.bit_vector.current_supported = *value;
+
+ return DS_SUCCESS;
+}
+
+void dal_ds_dispatch_update_adj_container_for_path_with_edid(
+ struct ds_dispatch *ds,
+ struct display_path *path)
+{
+ uint32_t index = dal_display_path_get_display_index(path);
+ struct adj_container *container;
+
+ if (!path)
+ dal_logger_write(ds->dal_context->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "display_path is unknown");
+ container = dal_ds_dispatch_get_adj_container_for_path(ds, index);
+ dal_adj_container_update_display_cap(container, path);
+ dal_adj_container_update_signal_type(
+ container,
+ dal_display_path_get_query_signal(path, SINK_LINK_INDEX));
+ build_adj_container_for_path(ds, path);
+}
+
+void dal_ds_dispatch_update_adj_container_for_path_with_mode_info(
+ struct ds_dispatch *ds,
+ struct display_path *display_path,
+ const struct path_mode *path_mode)
+{
+ uint32_t index = dal_display_path_get_display_index(display_path);
+ struct adj_container *container;
+
+ if (!display_path)
+ dal_logger_write(ds->dal_context->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "display_path is unknown");
+ container = dal_ds_dispatch_get_adj_container_for_path(ds, index);
+ if (container) {
+ dal_adj_container_update_timing_mode(
+ container,
+ &path_mode->mode_timing->mode_info,
+ &path_mode->view);
+ dal_ds_dispatch_update_adj_container_for_path_with_edid(
+ ds,
+ display_path);
+ }
+
+}
+
+static enum ds_signal_type get_ds_signal_from_display_path(
+ struct ds_dispatch *ds,
+ struct display_path *display_path,
+ uint32_t idx)
+{ enum ds_signal_type ds_signal = DS_SIGNAL_TYPE_CRT;
+ enum signal_type signal = dal_display_path_get_query_signal(
+ display_path,
+ SINK_LINK_INDEX);
+ switch (signal) {
+ case SIGNAL_TYPE_DVI_SINGLE_LINK:
+ case SIGNAL_TYPE_DVI_SINGLE_LINK1:
+ case SIGNAL_TYPE_DVI_DUAL_LINK:
+ ds_signal = DS_SIGNAL_TYPE_DFP;
+ break;
+ case SIGNAL_TYPE_HDMI_TYPE_A:
+ ds_signal = DS_SIGNAL_TYPE_HDMI;
+ break;
+ case SIGNAL_TYPE_DISPLAY_PORT:
+ case SIGNAL_TYPE_DISPLAY_PORT_MST:
+ ds_signal = DS_SIGNAL_TYPE_DP;
+ break;
+ case SIGNAL_TYPE_EDP:
+ ds_signal = DS_SIGNAL_TYPE_EDP;
+ break;
+ case SIGNAL_TYPE_RGB:
+ if (dal_dcs_is_non_continous_frequency(
+ dal_display_path_get_dcs(display_path)))
+ ds_signal = DS_SIGNAL_TYPE_DISCRETEVGA;
+ else
+ ds_signal = DS_SIGNAL_TYPE_CRT;
+ break;
+ case SIGNAL_TYPE_MVPU_A:
+ case SIGNAL_TYPE_MVPU_B:
+ case SIGNAL_TYPE_MVPU_AB:
+ ds_signal = DS_SIGNAL_TYPE_CF;
+ break;
+ case SIGNAL_TYPE_WIRELESS:
+ ds_signal = DS_SIGNAL_TYPE_WIRELESS;
+ break;
+ default:
+ ds_signal = DS_SIGNAL_TYPE_UNKNOWN;
+ dal_logger_write(ds->dal_context->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "dignal type is unknown");
+ break;
+ }
+ return ds_signal;
+}
+
+struct adj_container *dal_ds_dispatch_get_adj_container_for_path(
+ const struct ds_dispatch *ds,
+ uint32_t display_index)
+{
+
+ if (display_index < ds->disp_path_num)
+ return ds->applicable_adj[display_index];
+ return NULL;
+}
+
+bool dal_ds_dispatch_initialize_adjustment(struct ds_dispatch *ds)
+{
+ uint32_t i;
+ uint32_t num;
+
+ /* TODO unnecesary init_data. can just pass ds */
+ struct backlight_adj_group_init_data backlight_init_data;
+ struct single_adj_group_init_data single_init_data;
+ struct grph_colors_group_init_data colors_init_data;
+ struct grph_gamma_lut_group_init_data gamma_init_data;
+
+ ds->disp_path_num = dal_tm_get_num_display_paths(ds->tm, false);
+ num = ds->disp_path_num;
+
+ if (num == 0)
+ return false;
+
+ ds->applicable_adj = dal_alloc((sizeof(*ds->applicable_adj) * num));
+ if (ds->applicable_adj == NULL)
+ return false;
+ for (i = 0; i < num; i++) {
+ ds->applicable_adj[i] = dal_adj_container_create();
+ if (!ds->applicable_adj[i]) {
+ dal_logger_write(
+ ds->dal_context->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "initilize_adjustment has error");
+ dal_adj_container_destroy(ds->applicable_adj);
+ return false;
+ }
+ }
+
+ ds->default_adjustments = dal_adj_parent_api_create();
+ if (!ds->default_adjustments)
+ return false;
+ dal_adj_parent_api_build_child_objs(ds->default_adjustments);
+
+ backlight_init_data.ds = ds;
+ backlight_init_data.as = ds->as;
+ backlight_init_data.hws = ds->hwss;
+ backlight_init_data.tm = ds->tm;
+ backlight_init_data.dal_context = ds->dal_context;
+ ds->backlight_adj = dal_backlight_adj_group_create(
+ &backlight_init_data);
+ if (!ds->backlight_adj) {
+ dal_ds_dispatch_cleanup_adjustment(ds);
+ return false;
+ }
+ single_init_data.ds = ds;
+ single_init_data.hws = ds->hwss;
+ single_init_data.tm = ds->tm;
+ single_init_data.dal_context = ds->dal_context;
+ ds->single_adj = dal_single_adj_group_create(&single_init_data);
+
+ if (!ds->single_adj) {
+ dal_ds_dispatch_cleanup_adjustment(ds);
+ return false;
+ }
+ colors_init_data.ds = ds;
+ colors_init_data.hws = ds->hwss;
+ colors_init_data.dal_context = ds->dal_context;
+ ds->grph_colors_adj =
+ dal_grph_colors_group_create(&colors_init_data);
+ if (!ds->grph_colors_adj) {
+ dal_ds_dispatch_cleanup_adjustment(ds);
+ return false;
+ }
+
+ gamma_init_data.ds = ds;
+ gamma_init_data.hws = ds->hwss;
+ gamma_init_data.dal_context = ds->dal_context;
+ ds->grph_gamma_adj = dal_gamma_adj_group_create(&gamma_init_data);
+ if (!ds->grph_gamma_adj) {
+ dal_ds_dispatch_cleanup_adjustment(ds);
+ return false;
+ }
+
+ return true;
+}
+
+void dal_ds_dispatch_cleanup_adjustment(struct ds_dispatch *ds)
+{
+ uint32_t i;
+ uint32_t num;
+
+ num = ds->disp_path_num;
+
+ for (i = 0; i < num; i++)
+ dal_adj_container_destroy(ds->applicable_adj + i);
+ dal_free(ds->applicable_adj);
+
+ if (ds->default_adjustments)
+ dal_adj_parent_api_destroy(&ds->default_adjustments);
+
+ if (ds->backlight_adj != NULL)
+ dal_backlight_adj_group_destroy(&ds->backlight_adj);
+
+ if (ds->single_adj != NULL)
+ dal_single_adj_group_destroy(&ds->single_adj);
+
+ if (ds->grph_colors_adj != NULL)
+ dal_grph_colors_adj_group_destroy(&ds->grph_colors_adj);
+
+ if (ds->grph_gamma_adj != NULL)
+ dal_grph_gamma_adj_group_destroy(&ds->grph_gamma_adj);
+
+}
+
+bool dal_ds_dispatch_build_post_set_mode_adj(
+ struct ds_dispatch *ds,
+ const struct path_mode *mode,
+ struct display_path *display_path,
+ struct hw_adjustment_set *set)
+{
+ /*TODO: add implementation*/
+ return false;
+}
+
+bool dal_ds_dispatch_apply_scaling(
+ struct ds_dispatch *ds,
+ const struct path_mode *mode,
+ struct adj_container *container,
+ enum build_path_set_reason reason,
+ struct hw_path_mode *hw_path_mode)
+{
+ enum adjustment_id adj_id = ADJ_ID_UNDERSCAN;
+ struct ds_adjustment_scaler scaler;
+ const struct adjustment_info *info;
+ struct adj_container *set;
+
+ if (!hw_path_mode || !container)
+ return false;
+ info = dal_adj_info_set_get_adj_info(&container->adj_info_set, adj_id);
+
+ if (!info)
+ return false;
+ if (reason == BUILD_PATH_SET_REASON_FALLBACK_UNDERSCAN &&
+ hw_path_mode->action == HW_PATH_ACTION_SET) {
+ set = dal_ds_dispatch_get_adj_container_for_path(
+ ds,
+ mode->display_path_index);
+ dal_adj_info_set_update_cur_value(
+ &set->adj_info_set, adj_id, 0);
+ }
+ if (!dal_scaler_adj_group_build_scaler_parameter(
+ mode,
+ container,
+ reason,
+ adj_id,
+ info->adj_data.ranged.cur,
+ NULL,
+ hw_path_mode->display_path,
+ &scaler))
+ return false;
+ return dal_scaler_adj_group_apply_scaling(
+ &scaler,
+ container,
+ reason,
+ hw_path_mode);
+}
+
+bool dal_ds_dispatch_is_adjustment_supported(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ enum adjustment_id adjust_id)
+{
+ struct display_path *display_path =
+ dal_tm_display_index_to_display_path(
+ ds->tm, display_index);
+ return is_adjustment_supported(ds, display_path, adjust_id);
+}
+
+enum ds_return dal_ds_dispatch_get_property(
+ struct ds_dispatch *adj,
+ uint32_t display_index,
+ enum adjustment_id adjust_id,
+ union adjustment_property *property)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_ds_dispatch_set_adjustment(
+ struct ds_dispatch *ds,
+ const uint32_t display_index,
+ enum adjustment_id adjust_id,
+ int32_t value)
+{
+ enum ds_return result = DS_ERROR;
+ struct display_path *display_path =
+ dal_tm_display_index_to_display_path(
+ ds->tm, display_index);
+ if (display_path == NULL || !is_adjustment_supported(
+ ds, display_path, adjust_id)) {
+ dal_logger_write(ds->dal_context->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "display path is NULL");
+ return DS_ERROR;
+ }
+ switch (adjust_id) {
+ case ADJ_ID_SATURATION:
+ result = dal_grph_colors_group_set_adjustment(
+ ds->grph_colors_adj,
+ display_path,
+ adjust_id,
+ value);
+ break;
+
+ case ADJ_ID_UNDERSCAN:
+ case ADJ_ID_UNDERSCAN_TYPE:
+ result = dal_scaler_adj_group_set_adjustment(
+ ds,
+ display_index,
+ display_path,
+ adjust_id,
+ value);
+ break;
+
+ case ADJ_ID_BACKLIGHT:
+ result = dal_backlight_adj_group_set_adjustment(
+ ds->backlight_adj,
+ display_path,
+ adjust_id,
+ value);
+ break;
+ case ADJ_ID_BIT_DEPTH_REDUCTION:
+ result = dal_single_adj_group_set_adjustment(
+ ds->single_adj,
+ display_path,
+ adjust_id,
+ value);
+ break;
+ default:
+ dal_logger_write(ds->dal_context->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "set_adjustment failed");
+ result = DS_ERROR;
+ }
+ return result;
+}
+
+enum ds_return dal_ds_dispatch_set_gamma_adjustment(struct ds_dispatch *ds,
+ uint32_t display_index, enum adjustment_id adjust_id,
+ const struct raw_gamma_ramp *gamma) {
+ struct adj_container *adj_container = NULL;
+ const struct adjustment_info *cont_info = NULL;
+ const struct ds_regamma_lut *regumma_lut = NULL;
+ struct display_path *disp_path;
+ const struct path_mode *disp_path_mode;
+
+ if (ds == NULL)
+ return DS_ERROR;
+
+ disp_path = dal_tm_display_index_to_display_path(
+ ds->tm, display_index);
+
+ disp_path_mode = dal_pms_with_data_get_path_mode_for_display_index(
+ ds->set,
+ display_index);
+
+ if (disp_path == NULL || disp_path_mode == NULL)
+ return DS_ERROR;
+
+ adj_container = dal_ds_dispatch_get_adj_container_for_path(ds,
+ display_index);
+
+ if (adj_container == NULL)
+ return DS_ERROR;
+
+ cont_info = dal_adj_info_set_get_adj_info(&adj_container->adj_info_set,
+ adjust_id);
+
+ if (cont_info == NULL)
+ return DS_ERROR;
+
+ if (disp_path == NULL || cont_info == NULL ||
+ !is_adjustment_supported(ds, disp_path, adjust_id))
+ return DS_ERROR;
+
+ if (!is_adjustment_supported(ds, disp_path, adjust_id))
+ return DS_ERROR;
+
+ regumma_lut = dal_adj_container_get_regamma(
+ adj_container);
+
+ if (regumma_lut == NULL)
+ return DS_ERROR;
+
+ if (dal_grph_gamma_lut_set_adjustment(ds, disp_path, disp_path_mode,
+ adjust_id, gamma, regumma_lut))
+ return DS_SUCCESS;
+
+ return DS_ERROR;
+}
+
+const struct raw_gamma_ramp *dal_ds_dispatch_get_current_gamma(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ enum adjustment_id adjust_id)
+{
+ /*TODO: add implementation*/
+ return NULL;
+}
+
+const struct raw_gamma_ramp *dal_ds_dispatch_get_default_gamma(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ enum adjustment_id adjust_id)
+{
+ /*TODO: add implementation*/
+ return NULL;
+}
+
+enum ds_return dal_ds_dispatch_set_current_gamma(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ enum adjustment_id adjust_id,
+ const struct raw_gamma_ramp *gamma)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_ds_dispatch_set_gamma(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ enum adjustment_id adjust_id,
+ const struct raw_gamma_ramp *gamma)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+bool dal_ds_dispatch_get_underscan_info(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ struct ds_underscan_info *info)
+{
+ bool result = false;
+ struct display_path *display_path =
+ dal_tm_display_index_to_display_path(
+ ds->tm, display_index);
+ const struct path_mode *path_mode =
+ dal_pms_with_data_get_path_mode_for_display_index(
+ ds->set, display_index);
+ if (!display_path || !path_mode)
+ return false;
+ /*TODO: add implementation*
+ * result = scaler_adj->get_underscan_info();*/
+ return result;
+}
+
+bool dal_ds_dispatch_get_underscan_mode(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ struct ds_underscan_desc *desc)
+{
+ /*TODO: add implementation*/
+ return false;
+}
+
+bool dal_ds_dispatch_set_underscan_mode(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ struct ds_underscan_desc *desc)
+{
+ /*TODO: add implementation*/
+ return false;
+}
+
+bool dal_ds_dispatch_setup_overlay(
+ struct ds_dispatch *adj,
+ uint32_t display_index,
+ struct overlay_data *data)
+{
+ /*TODO: add implementation*/
+ return false;
+}
+
+void dal_ds_dispatch_set_applicable_adj(
+ struct ds_dispatch *adj,
+ uint32_t display_index,
+ const struct adj_container *applicable)
+{
+ /*TODO: add implementation*/
+}
+
+enum ds_return dal_ds_dispatch_set_color_gamut(
+ struct ds_dispatch *adj,
+ uint32_t display_index,
+ const struct ds_set_gamut_data *data)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_ds_dispatch_get_color_gamut(
+ struct ds_dispatch *adj,
+ uint32_t display_index,
+ const struct ds_gamut_reference_data *ref,
+ struct ds_get_gamut_data *data)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_ds_dispatch_get_color_gamut_info(
+ struct ds_dispatch *adj,
+ uint32_t display_index,
+ const struct ds_gamut_reference_data *ref,
+ struct ds_gamut_info *data)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_ds_dispatch_get_regamma_lut(
+ struct ds_dispatch *adj,
+ uint32_t display_index,
+ struct ds_regamma_lut *data)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_ds_dispatch_set_regamma_lut(
+ struct ds_dispatch *adj,
+ uint32_t display_index,
+ struct ds_regamma_lut *data)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_ds_dispatch_set_info_packets(
+ struct ds_dispatch *adj,
+ uint32_t display_index,
+ const struct info_frame *info_frames)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_ds_dispatch_get_info_packets(
+ struct ds_dispatch *adj,
+ uint32_t display_index,
+ struct info_frame *info_frames)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+static void build_adj_container_for_path(
+ struct ds_dispatch *ds,
+ struct display_path *display_path)
+{
+ uint32_t index = 0;
+ uint32_t i = 0;
+
+ struct adjustment_info info;
+ struct adj_container *container = NULL;
+
+ dal_memset(&info, 0, sizeof(struct adjustment_info));
+ index = dal_display_path_get_display_index(display_path);
+ if (!display_path)
+ dal_logger_write(ds->dal_context->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "display_path is unknown");
+ container = dal_ds_dispatch_get_adj_container_for_path(ds, index);
+
+ if (!container)
+ return;
+
+ if (!dal_adj_container_is_update_required(container))
+ return;
+
+ dal_adj_info_set_clear(&container->adj_info_set);
+
+ build_gamut_adj_for_path(ds, index, container, display_path);
+
+ for (i = ADJ_ID_BEGIN; i < ADJ_ID_END; i++) {
+ enum adjustment_id adj_id = i;
+
+ if (is_adjustment_supported(ds, display_path, adj_id)) {
+ if (DS_SUCCESS != get_adj_info_from_defaults(
+ ds,
+ index,
+ display_path,
+ adj_id,
+ &info))
+ continue;
+ if (DS_SUCCESS != get_adj_property(
+ ds,
+ index,
+ adj_id,
+ &info.adj_prop))
+ continue;
+ info.adj_id = adj_id;
+ info.adj_state = ADJUSTMENT_STATE_VALID;
+ dal_adj_info_set_add_adj_info(
+ &container->adj_info_set,
+ &info);
+ if (ADJ_RANGED == info.adj_data_type) {
+ dal_ds_dispatch_get_adjustment_current_value(
+ ds,
+ container,
+ &info,
+ adj_id,
+ true);
+ dal_adj_info_set_update_cur_value(
+ &container->adj_info_set,
+ adj_id,
+ info.adj_data.ranged.cur);
+ }
+
+ }
+ }
+
+ dal_adj_container_updated(container);
+}
+
+bool dal_ds_dispatch_include_adjustment(
+ struct ds_dispatch *ds,
+ struct display_path *disp_path,
+ struct ds_adj_id_value adj,
+ struct hw_adjustment_set *set)
+{
+ bool ret = false;
+
+ if (adj.adj_id == ADJ_ID_BIT_DEPTH_REDUCTION)
+ ret = dal_single_adj_group_include_adjustment(
+ ds->single_adj,
+ disp_path, adj, set);
+ return ret;
+}
+
+bool dal_ds_dispatch_build_include_adj(
+ struct ds_dispatch *ds,
+ const struct path_mode *mode,
+ struct display_path *display_path,
+ struct hw_path_mode *hw_mode,
+ struct hw_adjustment_set *set)
+{
+ /* TODO implement build_include_adjustments */
+ return false;
+}
+
+bool dal_ds_dispatch_build_color_control_adj(
+ struct ds_dispatch *ds,
+ const struct path_mode *mode,
+ struct display_path *disp_path,
+ struct hw_adjustment_set *set)
+{
+ if (!ds->grph_colors_adj || !disp_path)
+ return false;
+
+ return dal_grph_colors_group_build_color_control_adj(
+ ds->grph_colors_adj,
+ mode,
+ disp_path,
+ set);
+}
+
+void dal_ds_dispatch_update_adj_container_for_path_with_color_space(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ enum ds_color_space color_space)
+{
+ struct adj_container *adj_container;
+
+ adj_container = dal_ds_dispatch_get_adj_container_for_path(
+ ds, display_index);
+
+ if (adj_container != NULL)
+ dal_adj_container_update_color_space(
+ adj_container,
+ color_space);
+}
diff --git a/drivers/gpu/drm/amd/dal/display_service/ds_dispatch_info_frame.c b/drivers/gpu/drm/amd/dal/display_service/ds_dispatch_info_frame.c
new file mode 100644
index 000000000000..8adff1106d98
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/ds_dispatch_info_frame.c
@@ -0,0 +1,957 @@
+/*
+ * Copyright 2015 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/set_mode_types.h"
+#include "include/hw_sequencer_types.h"
+#include "include/dcs_types.h"
+#include "include/logger_interface.h"
+#include "include/adjustment_interface.h"
+#include "include/display_path_interface.h"
+#include "include/timing_service_interface.h"
+#include "include/topology_mgr_interface.h"
+
+#include "ds_dispatch.h"
+#include "adjustment_container.h"
+#include "grph_colors_group.h"
+#include "adjustment_types_internal.h"
+#include "ds_translation.h"
+
+/*
+ * build_itc_cn0_cn1_flags
+ *
+ * @brief
+ * build ITC, CN0 & CN1 flags
+ *
+ * ITC flag value comes from AVI Info Frame (GetAdjustmentVal)
+ * If ITC flag is enabled, itc is set to 1
+ * Support for CNC content is retrieved from CEA Block-Byte 8
+ * (GetCeaVendorSpecificDataBlock)
+ * If the content being sent is photo, cinema, or game, and the EDID does
+ * not have the corresponding CNC flag set, ITC has to be 0 and (CN1, CN0)
+ * have to be (0, 0) in order to meet HDMI compliance.
+ *
+ * @param
+ * const struct adj_container *adj_container
+ * - [in] adjustment container
+ * const uint32_t disp_index - [in] display index
+ * bool *itc - [out] ITC flag
+ * uint8_t *cn0_cn1 - [out] CN0 CN1 flags
+ *
+ * @return
+ * void
+ */
+static void build_itc_cn0_cn1_flags(
+ const struct adj_container *adj_container, bool *itc,
+ uint8_t *cn0_cn1)
+{
+ uint32_t itc_flag = 0;
+ uint32_t cn0_cn1_temp = 0;
+ enum display_content_type display_content;
+ union display_content_support support;
+
+ /* Initialize output values */
+ *itc = true;
+ *cn0_cn1 = 0;
+
+ /* Check what kind of content display could support */
+ if (adj_container == NULL
+ || !dal_adj_container_get_display_content_capability(
+ adj_container, &support))
+ return;
+
+ if (!dal_adj_container_get_adjustment_val(adj_container,
+ ADJ_ID_ITC_ENABLE, &itc_flag)) {
+ /* This case is valid for:
+ * 1) non HDMI */
+ *itc = false;
+ return;
+ }
+
+ if (!dal_adj_container_get_adjustment_val(adj_container,
+ ADJ_ID_CNC_CONTENT, &cn0_cn1_temp))
+ /* This case is valid for:
+ * 1) non HDMI */
+ return;
+
+ *itc = itc_flag > 0;
+
+ if (itc_flag == 0) {
+ *cn0_cn1 = 0;
+ return;
+ }
+
+ /* Get the requested content type from adjustment value */
+ dal_ds_translation_translate_content_type(cn0_cn1_temp,
+ &display_content);
+
+ if (!support.bits.VALID_CONTENT_TYPE)
+ /* We are dealing with HDMI version < 1.4 where CNC flags were
+ * not defined (i.e. these fields are reserved and are set to 0)
+ * In this case, we are allowed to support ITC if user wants it
+ * (CN1, CN0) are set to (0, 0) since they are reserved fields
+ * in HDMI version < 1.4 */
+ *cn0_cn1 = 0;
+ else {
+ /* We are dealing with HDMI version 1.4 or later where
+ * CNC flags can be read from the vendor specific data block */
+ if (display_content == DISPLAY_CONTENT_TYPE_GRAPHICS) {
+ /* In this case, ITC = 1 or ITC = 0. */
+ if (support.bits.GRAPHICS_CONTENT == 1)
+ *cn0_cn1 = 0;
+ } else if (display_content == DISPLAY_CONTENT_TYPE_PHOTO) {
+ if (support.bits.PHOTO_CONTENT == 1)
+ *cn0_cn1 = 1;
+ else {
+ /* To pass HDMI compliance test,
+ * ITC = 0, and (CN1, CN0) = (0, 0) */
+ *cn0_cn1 = 0;
+ *itc = 0;
+ }
+ } else if (display_content == DISPLAY_CONTENT_TYPE_CINEMA) {
+ if (support.bits.CINEMA_CONTENT == 1)
+ *cn0_cn1 = 2;
+ else {
+ /* To pass HDMI compliance test,
+ *ITC = 0, and (CN1, CN0) = (0, 0) */
+ *cn0_cn1 = 0;
+ *itc = 0;
+ }
+ } else if (display_content == DISPLAY_CONTENT_TYPE_GAME) {
+ if (support.bits.GAME_CONTENT == 1)
+ *cn0_cn1 = 3;
+ else {
+ /* To pass HDMI compliance test,
+ * ITC = 0, and (CN1, CN0) = (0, 0) */
+ *cn0_cn1 = 0;
+ *itc = 0;
+ }
+ }
+ }
+}
+
+/*
+ * ds_prepare_avi_info_frame
+ *
+ * @brief
+ * Build AVI info frame
+ *
+ * @param
+ * const struct path_mode *mode - [in] path mode
+ * const struct display_path *disp_path - [in] display path
+ * const struct hw_overscan overscan - [in] overscan config
+ * const struct hw_scale_options underscan_rule -[in] scale options
+ * struct hw_info_packet *info_packet - [out] info frame packet being set
+ *
+ * @return
+ * void
+ */
+static void prepare_avi_info_frame(struct ds_dispatch *ds_dispatch,
+ const struct path_mode *mode,
+ const struct display_path *disp_path,
+ const struct overscan_info overscan,
+ const enum hw_scale_options underscan_rule,
+ struct hw_info_packet *info_packet)
+{
+ struct adj_container *adj_container = NULL;
+ enum ds_color_space color_space = DS_COLOR_SPACE_UNKNOWN;
+ bool extended_colorimetry = false;
+ struct info_frame info_frame = { {0} };
+ uint32_t pixel_encoding = 0;
+ enum scanning_type scan_type = SCANNING_TYPE_NODATA;
+ enum aspect_ratio aspect = ASPECT_RATIO_NO_DATA;
+ bool itc = false;
+ uint8_t cn0_cn1 = 0;
+ union cea_video_capability_data_block video_cap;
+ bool video_cap_support = false;
+ uint32_t hw_pixel_repetition = 0;
+ uint8_t *check_sum = NULL;
+ uint8_t byte_index = 0;
+
+ if (mode == NULL || info_packet == NULL || mode->mode_timing == NULL
+ || disp_path == NULL) {
+ dal_logger_write(ds_dispatch->dal_context->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "Invalid parameters");
+ return;
+ }
+
+ /* TODO: Adjustment implementation. */
+ adj_container = dal_ds_dispatch_get_adj_container_for_path(
+ ds_dispatch, mode->display_path_index);
+
+ /* TODO: Verify adjustment container
+ if (adj_container == NULL) {
+ dal_logger_write(ds_dispatch->dal_context,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "Invalid adjustment container");
+ return;
+ }
+ */
+
+ color_space = dal_grph_colors_group_get_color_space(
+ ds_dispatch->grph_colors_adj,
+ &mode->mode_timing->crtc_timing,
+ disp_path,
+ adj_container);
+
+ /* TODO: Verify colors group
+ if (color_space == DS_COLOR_SPACE_UNKNOWN) {
+ dal_logger_write(ds_dispatch->dal_context,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "Invalid color space");
+ return;
+ }
+ */
+
+ extended_colorimetry = dal_ds_dispatch_is_gamut_change_required(
+ ds_dispatch,
+ mode->mode_timing->crtc_timing.pixel_encoding,
+ mode->pixel_format, mode->display_path_index);
+
+ /* Initialize header */
+ info_frame.avi_info_packet.info_packet.bits.header.info_frame_type =
+ INFO_FRAME_AVI;
+ /* InfoFrameVersion_3 is defined by CEA861F (Section 6.4), but shall
+ * not be used in HDMI 2.0 (Section 10.1) */
+ info_frame.avi_info_packet.info_packet.bits.header.version =
+ INFO_FRAME_VERSION_2;
+ info_frame.avi_info_packet.info_packet.bits.header.length =
+ INFO_FRAME_SIZE_AVI;
+
+ /* IDO-defined (Y2,Y1,Y0 = 1,1,1) shall not be used by devices built
+ * according to HDMI 2.0 spec (Section 10.1)
+ * Add "case PixelEncoding_YCbCr420: pixelEncoding = 3; break;"
+ * when YCbCr 4:2:0 is supported by DAL hardware. */
+ switch (mode->mode_timing->crtc_timing.pixel_encoding) {
+ case PIXEL_ENCODING_YCBCR422:
+ pixel_encoding = 1;
+ break;
+
+ case PIXEL_ENCODING_YCBCR444:
+ pixel_encoding = 2;
+ break;
+
+ case PIXEL_ENCODING_RGB:
+ default:
+ pixel_encoding = 0;
+ }
+
+ /* Y0_Y1_Y2 : The pixel encoding */
+ /* H14b AVI InfoFrame has extension on Y-field from 2 bits to 3 bits */
+ info_frame.avi_info_packet.info_packet.bits.Y0_Y1_Y2 = pixel_encoding;
+
+ dal_logger_write(ds_dispatch->dal_context->logger,
+ LOG_MAJOR_INFO_PACKETS,
+ LOG_MINOR_INFO_PACKETS_HDMI,
+ "====AVIInfoFrame pixEnc (%d) %s===",
+ info_frame.avi_info_packet.info_packet.bits.Y0_Y1_Y2,
+ pixel_encoding == 1 ? "YCbCr422" :
+ pixel_encoding == 2 ? "YCbCr444" : "RGB");
+
+ /* A0 = 1 Active Format Information valid */
+ info_frame.avi_info_packet.info_packet.bits.A0 = ACTIVE_FORMAT_VALID;
+
+ /* B0, B1 = 3; Bar info data is valid */
+ info_frame.avi_info_packet.info_packet.bits.B0_B1 = BAR_INFO_BOTH_VALID;
+
+ info_frame.avi_info_packet.info_packet.bits.SC0_SC1 =
+ PICTURE_SCALING_UNIFORM;
+
+ /* S0, S1 : Underscan / Overscan */
+
+ if (dal_adj_container_get_scan_type(adj_container, &scan_type))
+ info_frame.avi_info_packet.info_packet.bits.S0_S1 = scan_type;
+ else
+ info_frame.avi_info_packet.info_packet.bits.S0_S1 =
+ underscan_rule;
+
+ dal_logger_write(ds_dispatch->dal_context->logger,
+ LOG_MAJOR_INFO_PACKETS,
+ LOG_MINOR_INFO_PACKETS_HDMI, "scanType (%d) %s",
+ info_frame.avi_info_packet.info_packet.bits.S0_S1,
+ info_frame.avi_info_packet.info_packet.bits.S0_S1 == 1 ?
+ "Overscan" :
+ info_frame.avi_info_packet.info_packet.bits.S0_S1 == 2 ?
+ "Underscan" : "Unknown");
+
+ /* C0, C1 : Colorimetry */
+ if (color_space == DS_COLOR_SPACE_YPBPR709)
+ info_frame.avi_info_packet.info_packet.bits.C0_C1 =
+ COLORIMETRY_ITU709;
+ else if (color_space == DS_COLOR_SPACE_YPBPR601)
+ info_frame.avi_info_packet.info_packet.bits.C0_C1 =
+ COLORIMETRY_ITU601;
+ else
+ info_frame.avi_info_packet.info_packet.bits.C0_C1 =
+ COLORIMETRY_NO_DATA;
+
+ /* EC2,EC1,EC0 - Valid only if C0,C1 = 1,1 */
+
+ if (extended_colorimetry) {
+ /* GBD enabled, we need update EC0~EC2,
+ * also change C0, C1 to 1, 1. */
+ if (info_frame.avi_info_packet.info_packet.bits.C0_C1
+ == COLORIMETRY_ITU601)
+ info_frame.avi_info_packet.info_packet.bits.EC0_EC2 =
+ COLORIMETRY_EX_XVYCC601;
+ else if (info_frame.avi_info_packet.info_packet.bits.C0_C1
+ == COLORIMETRY_ITU709)
+ info_frame.avi_info_packet.info_packet.bits.EC0_EC2 =
+ COLORIMETRY_EX_XVYCC709;
+
+ info_frame.avi_info_packet.info_packet.bits.C0_C1 =
+ COLORIMETRY_EXTENDED;
+ }
+
+ dal_logger_write(ds_dispatch->dal_context->logger,
+ LOG_MAJOR_INFO_PACKETS,
+ LOG_MINOR_INFO_PACKETS_HDMI, "colometry (%d) %s",
+ info_frame.avi_info_packet.info_packet.bits.C0_C1,
+ info_frame.avi_info_packet.info_packet.bits.C0_C1 == 1 ?
+ "ITU601" :
+ info_frame.avi_info_packet.info_packet.bits.C0_C1 == 2 ?
+ "ITU709" :
+ info_frame.avi_info_packet.info_packet.bits.C0_C1 == 3 ?
+ "Underscan" : "Unknown");
+
+ dal_logger_write(ds_dispatch->dal_context->logger,
+ LOG_MAJOR_INFO_PACKETS,
+ LOG_MINOR_INFO_PACKETS_HDMI, "excolometry (%d) %s",
+ info_frame.avi_info_packet.info_packet.bits.EC0_EC2,
+ info_frame.avi_info_packet.info_packet.bits.EC0_EC2
+ == 1 ? "xvYCC601" :
+ info_frame.avi_info_packet.info_packet.bits.EC0_EC2
+ == 2 ? "xvYCC709" : "not supported");
+
+ /* Get aspect ratio from timing service */
+ aspect = dal_timing_service_get_aspect_ratio_for_timing(ds_dispatch->ts,
+ &mode->mode_timing->crtc_timing);
+
+ switch (aspect) {
+ case ASPECT_RATIO_4_3:
+ case ASPECT_RATIO_16_9:
+ info_frame.avi_info_packet.info_packet.bits.M0_M1 = aspect;
+ break;
+
+ case ASPECT_RATIO_NO_DATA:
+ default:
+ info_frame.avi_info_packet.info_packet.bits.M0_M1 = 0;
+ }
+
+ dal_logger_write(ds_dispatch->dal_context->logger,
+ LOG_MAJOR_INFO_PACKETS,
+ LOG_MINOR_INFO_PACKETS_HDMI, "aspect ratio (%d) %s",
+ info_frame.avi_info_packet.info_packet.bits.M0_M1,
+ info_frame.avi_info_packet.info_packet.bits.M0_M1 == 1 ?
+ "4_3" :
+ info_frame.avi_info_packet.info_packet.bits.M0_M1 == 2 ?
+ "16_9" : "unknown");
+
+ /* Active Format Aspect ratio - same as Picture Aspect Ratio. */
+ info_frame.avi_info_packet.info_packet.bits.R0_R3 =
+ ACTIVE_FORMAT_ASPECT_RATIO_SAME_AS_PICTURE;
+
+ /* Check for ITC Flag and CNC content Value from AVI Info Packet
+ * the method always set the required values */
+ build_itc_cn0_cn1_flags(adj_container, &itc, &cn0_cn1);
+
+ if (itc) {
+ info_frame.avi_info_packet.info_packet.bits.ITC = 1;
+ info_frame.avi_info_packet.info_packet.bits.CN0_CN1 = cn0_cn1;
+ }
+
+ dal_logger_write(ds_dispatch->dal_context->logger,
+ LOG_MAJOR_INFO_PACKETS,
+ LOG_MINOR_INFO_PACKETS_HDMI, "Itc %d CNC %d",
+ info_frame.avi_info_packet.info_packet.bits.ITC,
+ info_frame.avi_info_packet.info_packet.bits.CN0_CN1);
+
+ video_cap_support =
+ dal_adj_container_get_cea_video_cap_data_block(
+ adj_container, &video_cap);
+
+ if (video_cap_support && video_cap.bits.QS == 1) {
+ if (color_space == DS_COLOR_SPACE_SRGB_FULLRANGE)
+ info_frame.avi_info_packet.info_packet.bits.Q0_Q1 =
+ RGB_QUANTIZATION_FULL_RANGE;
+ else if (color_space == DS_COLOR_SPACE_SRGB_LIMITEDRANGE)
+ info_frame.avi_info_packet.info_packet.bits.Q0_Q1 =
+ RGB_QUANTIZATION_LIMITED_RANGE;
+ else
+ info_frame.avi_info_packet.info_packet.bits.Q0_Q1 =
+ RGB_QUANTIZATION_DEFAULT_RANGE;
+ } else
+ info_frame.avi_info_packet.info_packet.bits.Q0_Q1 =
+ RGB_QUANTIZATION_DEFAULT_RANGE;
+
+ /* TODO : We should handle YCC quantization,
+ * but we do not have matrix calculation */
+ if (video_cap_support && video_cap.bits.QY == 1)
+ info_frame.avi_info_packet.info_packet.bits.YQ0_YQ1 =
+ RGB_QUANTIZATION_LIMITED_RANGE;
+ else
+ info_frame.avi_info_packet.info_packet.bits.YQ0_YQ1 =
+ RGB_QUANTIZATION_LIMITED_RANGE;
+
+ dal_logger_write(ds_dispatch->dal_context->logger,
+ LOG_MAJOR_INFO_PACKETS,
+ LOG_MINOR_INFO_PACKETS_HDMI, "RGB quantization %d %s",
+ info_frame.avi_info_packet.info_packet.bits.Q0_Q1,
+ info_frame.avi_info_packet.info_packet.bits.Q0_Q1 == 2 ?
+ "full rgb" :
+ info_frame.avi_info_packet.info_packet.bits.Q0_Q1 == 1 ?
+ "lim rgb" : "default");
+
+ dal_logger_write(ds_dispatch->dal_context->logger,
+ LOG_MAJOR_INFO_PACKETS,
+ LOG_MINOR_INFO_PACKETS_HDMI, "YCC quantization %d %s",
+ info_frame.avi_info_packet.info_packet.bits.YQ0_YQ1,
+ info_frame.avi_info_packet.info_packet.bits.YQ0_YQ1 ==
+ 0 ? "lim ycc" :
+ info_frame.avi_info_packet.info_packet.bits.YQ0_YQ1 ==
+ 1 ? "full ycc" : "reserved");
+
+ /* VIC */
+ info_frame.avi_info_packet.info_packet.bits.VIC0_VIC7 =
+ mode->mode_timing->crtc_timing.vic;
+
+ dal_logger_write(ds_dispatch->dal_context->logger,
+ LOG_MAJOR_INFO_PACKETS,
+ LOG_MINOR_INFO_PACKETS_HDMI, "VIC0_VIC7 %d",
+ info_frame.avi_info_packet.info_packet.bits.VIC0_VIC7);
+
+ hw_pixel_repetition =
+ mode->mode_timing->crtc_timing.flags.PIXEL_REPETITION
+ == 0 ? 1 :
+ mode->mode_timing->crtc_timing.flags.PIXEL_REPETITION;
+ /* pixel repetition
+ * PR0 - PR3 start from 0 whereas pHwPathMode->mode.timing.flags.pixel
+ * repetition start from 1 */
+ info_frame.avi_info_packet.info_packet.bits.PR0_PR3 =
+ hw_pixel_repetition - 1;
+
+ dal_logger_write(ds_dispatch->dal_context->logger,
+ LOG_MAJOR_INFO_PACKETS,
+ LOG_MINOR_INFO_PACKETS_HDMI, "Pixel repetition %d",
+ info_frame.avi_info_packet.info_packet.bits.PR0_PR3);
+
+ /* Bar Info
+ * barTop: Line Number of End of Top Bar.
+ * barBottom: Line Number of Start of Bottom Bar.
+ * barLeft: Pixel Number of End of Left Bar.
+ * barRight: Pixel Number of Start of Right Bar. */
+ info_frame.avi_info_packet.info_packet.bits.bar_top =
+ (uint16_t) overscan.top;
+ info_frame.avi_info_packet.info_packet.bits.bar_bottom =
+ (uint16_t) (mode->mode_timing->crtc_timing.v_border_top
+ - overscan.bottom + 1);
+ info_frame.avi_info_packet.info_packet.bits.bar_left =
+ (uint16_t) overscan.left;
+ info_frame.avi_info_packet.info_packet.bits.bar_right =
+ (uint16_t) (mode->mode_timing->crtc_timing.h_total
+ - overscan.right + 1);
+
+ dal_logger_write(ds_dispatch->dal_context->logger,
+ LOG_MAJOR_INFO_PACKETS,
+ LOG_MINOR_INFO_PACKETS_HDMI,
+ "top %d, bottom %d, left %d, right %d",
+ info_frame.avi_info_packet.info_packet.bits.bar_top,
+ info_frame.avi_info_packet.info_packet.bits.bar_bottom,
+ info_frame.avi_info_packet.info_packet.bits.bar_left,
+ info_frame.avi_info_packet.info_packet.bits.bar_right);
+
+ /* check_sum - Calculate AFMT_AVI_INFO0 ~ AFMT_AVI_INFO3 */
+ check_sum =
+ &info_frame.avi_info_packet.info_packet.packet_raw_data.sb[0];
+ *check_sum = INFO_FRAME_AVI + INFO_FRAME_SIZE_AVI
+ + INFO_FRAME_VERSION_2;
+
+ for (byte_index = 1; byte_index <= INFO_FRAME_SIZE_AVI; byte_index++)
+ *check_sum += info_frame.avi_info_packet.info_packet.
+ packet_raw_data.sb[byte_index];
+
+ /* one byte complement */
+ *check_sum = (uint8_t) (0x100 - *check_sum);
+
+ dal_logger_write(ds_dispatch->dal_context->logger,
+ LOG_MAJOR_INFO_PACKETS,
+ LOG_MINOR_INFO_PACKETS_HDMI, "===check sum %x===",
+ (uint32_t) *check_sum);
+
+ /* Store in hw_path_mode */
+ info_packet->hb0 =
+ info_frame.avi_info_packet.info_packet.packet_raw_data.hb0;
+ info_packet->hb1 =
+ info_frame.avi_info_packet.info_packet.packet_raw_data.hb1;
+ info_packet->hb2 =
+ info_frame.avi_info_packet.info_packet.packet_raw_data.hb2;
+
+ for (byte_index = 0; byte_index < sizeof(info_packet->sb); byte_index++)
+ info_packet->sb[byte_index] = info_frame.avi_info_packet.
+ info_packet.packet_raw_data.sb[byte_index];
+
+ info_packet->valid = true;
+}
+
+/*
+ * prepare_vendor_info_packet
+ *
+ * @brief
+ * Build vendor info frame
+ *
+ * Currently only thing we put in VSIF, is 3D stereo support
+ *
+ * @param
+ * mode - [in] path mode which contains data may need to construct VSIF
+ * pPacket - [out] output structre where to store VSIF
+ *
+ * @return
+ * void
+ */
+static void prepare_vendor_info_packet(const struct path_mode *mode,
+ struct hw_info_packet *info_packet)
+{
+ uint32_t length = 0;
+ bool hdmi_vic_mode = false;
+ uint8_t checksum = 0;
+ uint32_t i = 0;
+ enum timing_3d_format format;
+
+ ASSERT_CRITICAL(mode != NULL);
+ ASSERT_CRITICAL(info_packet != NULL);
+
+ format = dal_ds_translation_get_active_timing_3d_format(
+ mode->mode_timing->crtc_timing.timing_3d_format,
+ mode->view_3d_format);
+
+ /* Can be different depending on packet content */
+ length = 5;
+
+ if (mode->mode_timing->crtc_timing.hdmi_vic != 0 &&
+ mode->view.width >= 3840 &&
+ mode->view.height == 2160)
+ hdmi_vic_mode = true;
+
+ /* According to HDMI 1.4a CTS, VSIF should be sent
+ * for both 3D stereo and HDMI VIC modes.
+ * For all other modes, there is no VSIF sent. */
+
+ if (format == TIMING_3D_FORMAT_NONE && !hdmi_vic_mode)
+ return;
+
+ /* 24bit IEEE Registration identifier (0x000c03). LSB first. */
+ info_packet->sb[1] = 0x03;
+ info_packet->sb[2] = 0x0C;
+ info_packet->sb[3] = 0x00;
+
+ /*PB4: 5 lower bytes = 0 (reserved). 3 higher bits = HDMI_Video_Format.
+ * The value for HDMI_Video_Format are:
+ * 0x0 (0b000) - No additional HDMI video format is presented in this
+ * packet
+ * 0x1 (0b001) - Extended resolution format present. 1 byte of HDMI_VIC
+ * parameter follows
+ * 0x2 (0b010) - 3D format indication present. 3D_Structure and
+ * potentially 3D_Ext_Data follows
+ * 0x3..0x7 (0b011..0b111) - reserved for future use */
+ if (format != TIMING_3D_FORMAT_NONE)
+ info_packet->sb[4] = (2 << 5);
+ else if (hdmi_vic_mode)
+ info_packet->sb[4] = (1 << 5);
+
+ /* PB5: If PB4 claims 3D timing (HDMI_Video_Format = 0x2):
+ * 4 lower bites = 0 (reserved). 4 higher bits = 3D_Structure.
+ * The value for 3D_Structure are:
+ * 0x0 - Frame Packing
+ * 0x1 - Field Alternative
+ * 0x2 - Line Alternative
+ * 0x3 - Side-by-Side (full)
+ * 0x4 - L + depth
+ * 0x5 - L + depth + graphics + graphics-depth
+ * 0x6 - Top-and-Bottom
+ * 0x7 - Reserved for future use
+ * 0x8 - Side-by-Side (Half)
+ * 0x9..0xE - Reserved for future use
+ * 0xF - Not used */
+ switch (format) {
+ case TIMING_3D_FORMAT_HW_FRAME_PACKING:
+ case TIMING_3D_FORMAT_SW_FRAME_PACKING:
+ info_packet->sb[5] = (0x0 << 4);
+ break;
+
+ case TIMING_3D_FORMAT_SIDE_BY_SIDE:
+ case TIMING_3D_FORMAT_SBS_SW_PACKED:
+ info_packet->sb[5] = (0x8 << 4);
+ length = 6;
+ break;
+
+ case TIMING_3D_FORMAT_TOP_AND_BOTTOM:
+ case TIMING_3D_FORMAT_TB_SW_PACKED:
+ info_packet->sb[5] = (0x6 << 4);
+ break;
+
+ default:
+ break;
+ }
+
+ /*PB5: If PB4 is set to 0x1 (extended resolution format)
+ * fill PB5 with the correct HDMI VIC code */
+ if (hdmi_vic_mode)
+ info_packet->sb[5] =
+ (uint8_t) (mode->mode_timing->crtc_timing.hdmi_vic);
+
+ /* Header */
+ info_packet->hb0 = 0x81; /* VSIF packet type. */
+ info_packet->hb1 = 0x01; /* Version */
+
+ /* 4 lower bits = Length, 4 higher bits = 0 (reserved) */
+ info_packet->hb2 = (uint8_t) (length);
+
+ /* Calculate checksum */
+ checksum = 0;
+ checksum += info_packet->hb0;
+ checksum += info_packet->hb1;
+ checksum += info_packet->hb2;
+
+ for (i = 1; i <= length; i++)
+ checksum += info_packet->sb[i];
+
+ info_packet->sb[0] = (uint8_t) (0x100 - checksum);
+
+ info_packet->valid = true;
+}
+
+/*
+ * prepare_default_gamut_packet
+ *
+ * @brief
+ * Build default gamut packet
+ *
+ * @param
+ * mode - [in] path mode that contains the gamut change flag
+ *
+ * @return
+ * True if packet is buit. False otherwise.
+ */
+static bool prepare_default_gamut_packet(struct ds_dispatch *ds_dispatch,
+ const struct path_mode *mode,
+ struct hw_info_packet *info_packet)
+{
+ bool result = false;
+ uint8_t base = 0; /* GBD profile 0 */
+ uint32_t xgdb_color_precision = 0;
+ uint32_t xgdb_color_space = 0;
+ uint32_t xgdb_min_red_data = 0;
+ uint32_t xgdb_max_red_data = 0;
+ uint32_t xgdb_min_green_data = 0;
+ uint32_t xgdb_max_green_data = 0;
+ uint32_t xgdb_min_blue_data = 0;
+ uint32_t xgdb_max_blue_data = 0;
+
+ if (mode == NULL || mode->mode_timing == NULL)
+ return result;
+
+ if (!dal_ds_dispatch_is_gamut_change_required(
+ ds_dispatch,
+ mode->mode_timing->crtc_timing.pixel_encoding,
+ mode->pixel_format, mode->display_path_index))
+ return result;
+
+ /* uint32_t xgdb_format_Flag = 1; */
+
+ /* 0->8-bit precision
+ * 1->10-bit precision
+ * 2->12-bit precision */
+ xgdb_color_precision = 2;
+ xgdb_color_space = 2;
+ xgdb_min_red_data = 0x84f;
+ xgdb_max_red_data = 0x7ff;
+ xgdb_min_green_data = 0x84f;
+ xgdb_max_green_data = 0x7ff;
+ xgdb_min_blue_data = 0x84f;
+ xgdb_max_blue_data = 0x7ff;
+
+ /* Header */
+ info_packet->hb0 = 0x0A; /* Gamut packed type. */
+ info_packet->hb1 = 0x81; /* HDMI spec Rev1.3 page 78.
+ <these settings are recommended by OEM.) */
+ info_packet->hb2 = 0x31; /* page 78 //0x80 bit is for stop GBD use. */
+
+ /* translate to Fixed point format first:
+ * 1 signed bit, 2 bits integer, 9 bits fraction. */
+
+ /* Min_Red_H */
+ info_packet->sb[base + 1] |= (xgdb_min_red_data & 0xff0) >> 4;
+
+ /* Min_Red_L|MaxRed_H */
+ info_packet->sb[base + 2] |= (xgdb_min_red_data & 0x00f) << 4;
+ info_packet->sb[base + 2] |= (xgdb_max_red_data & 0xf00) >> 8;
+ info_packet->sb[base + 3] |= (xgdb_max_red_data & 0x0ff); /*Max_Red_L*/
+
+ /* Min_Green_H */
+ info_packet->sb[base + 4] |= (xgdb_min_green_data & 0xff0) >> 4;
+
+ /* Min_Green_L|MaxGreen_H */
+ info_packet->sb[base + 5] |= (xgdb_min_green_data & 0x00f) << 4;
+ info_packet->sb[base + 5] |= (xgdb_max_green_data & 0xf00) >> 8;
+
+ /* Max_Green_L */
+ info_packet->sb[base + 6] |= (xgdb_max_green_data & 0x0ff);
+
+ /* Min_Blue_H */
+ info_packet->sb[base + 7] |= (xgdb_min_blue_data & 0xff0) >> 4;
+
+ /* Min_Blue_L|MaxBlue_H */
+ info_packet->sb[base + 8] |= (xgdb_min_blue_data & 0x00f) << 4;
+ info_packet->sb[base + 8] |= (xgdb_max_blue_data & 0xf00) >> 8;
+
+ /* Max_Blue_L */
+ info_packet->sb[base + 9] |= (xgdb_max_blue_data & 0x0ff);
+
+ info_packet->sb[base + 0] |= 0x80; /* RANGE FORMAT */
+ info_packet->sb[base + 0] |= (xgdb_color_precision) << 0x3;
+ info_packet->sb[base + 0] |= (xgdb_color_space & 0x3);
+
+ info_packet->valid = true;
+ result = true;
+
+ return result;
+
+}
+
+/*
+ * ds_prepare_video_stream_configuration_packet
+ *
+ * @brief
+ * Build video stream configuration packet
+ *
+ * @param
+ *
+ * @return
+ * void
+ */
+static void prepare_video_stream_configuration_packet(
+ struct ds_dispatch *ds_dispatch,
+ const struct path_mode *mode,
+ struct hw_info_packet *info_packet)
+{
+ bool psr_panel_support = false;
+ enum timing_3d_format format;
+
+ /* Check for invalid input parameters */
+ if (mode == NULL || info_packet == NULL) {
+ dal_logger_write(ds_dispatch->dal_context->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "Invalid parameters");
+ return;
+ }
+
+ /* Check if timing is 3D format. If so, VSC packet should be updated to
+ * indicate to Sink we are outputting 3D. */
+ format = dal_ds_translation_get_active_timing_3d_format(
+ mode->mode_timing->crtc_timing.timing_3d_format,
+ mode->view_3d_format);
+
+ /* Check if PSR is supported. If so, we need to enable and send the VSC
+ * packet to allow DMCU to update PSR specific fields. */
+ if (dal_adapter_service_is_feature_supported(FEATURE_PSR_ENABLE)) {
+ struct display_path *display_path =
+ dal_tm_display_index_to_display_path(
+ ds_dispatch->tm,
+ mode->display_path_index);
+
+ if ((display_path != NULL) &&
+ (dal_display_path_is_psr_supported(
+ display_path)))
+ psr_panel_support = true;
+ }
+
+ /* Packet Header */
+ /* Secondary data packet ID byte 0 = 0h */
+ info_packet->hb0 = 0x00;
+ /* Secondary data packet ID byte 0 = 07h */
+ info_packet->hb1 = 0x07;
+
+ if (psr_panel_support) {
+ /* If PSR panel is supported, VSC packet header should be
+ * initialized with packet revision 2 set in byte 2 */
+ info_packet->hb2 = 0x02;
+
+ /* ===========================================================|
+ * PSR uses 7 Bytes. We need to set 8 Bytes here since 3D
+ * Stereo is occupying the first Byte in the VSC packet.
+ *
+ * ===========================================================|
+ * Byte 0 is set by driver for 3D Stereo purposes.
+ * -----------------------------------------------
+ *
+ * Byte 0 - Used by 3D Stereo. See (VSC Payload (1 byte)
+ * From DP1.2 spec) below for usage.
+ *
+ * ===========================================================|
+ * Bytes 1-7 are set by DMCU for PSR purposes.
+ * However, driver must enable and send the VSC packet by
+ * setting up the packet header. DMCU will only fill in the PSR
+ * specific fields in the VSC packet and must not modify
+ * non-PSR related fields.
+ * ------------------------------------------------------------
+ *
+ * Byte 1 - Used by DMCU to indicate action to panel.
+ * 1. PSR active (bit 0 - 0x1)
+ * 2. RFB update (bit 1 - 0x2)
+ * 3. CRC update (bit 2 - 0x4)
+ * Bytes 2-3- Used by DMCU for CRC by sending value of
+ * FMT_CRC_SIG_RED_GREEN:FMT_CRC_SIG_RED.
+ * Bytes 4-5- Used by DMCU for CRC by sending value of
+ * FMT_CRC_SIG_RED_GREEN:FMT_CRC_SIG_GREEN.
+ * Bytes 6-7- Used by DMCU for CRC by sending value of
+ * FMT_CRC_SIG_BLUE_CONTROL:FMT_CRC_SIG_BLUE.
+ *
+ * ==========================================================*/
+
+ /* Bits 4:0 = Number of valid data bytes = 08h,
+ * Bits 7:5 = RESERVED (all 0's)*/
+ info_packet->hb3 = 0x08;
+ info_packet->valid = true;
+ } else {
+ /* Bits 4:0 = Revision Number = 01h,
+ * Bits 7:5 = RESERVED (all 0's) */
+ info_packet->hb2 = 0x01;
+ /* Bits 4:0 = Number of valid data bytes = 01h
+ * Bits 7:5 = RESERVED (all 0's) */
+ info_packet->hb3 = 0x01;
+ }
+
+ /* Set VSC data fields for 3D Stereo if supported */
+ if (format != TIMING_3D_FORMAT_NONE) {
+ /* VSC Payload (1 byte) From DP1.2 spec
+ *
+ * Bits 3:0 | Bits 7:4
+ * (Stereo Interface | (Stereo Interface
+ * Method Code) | Method Specific Parameter)
+ * ------------------------------------------------------------
+ * 0 = Non Stereo Video | Must be set to 0x0
+ * ------------------------------------------------------------
+ * 1 = Frame/Field Sequential| 0x0: L + R view indication
+ * | based on MISC1 bit 2:1
+ * | 0x1: Right when Stereo
+ * | Signal = 1
+ * | 0x2: Left when Stereo
+ * | Signal = 1
+ * | (others reserved)
+ * ------------------------------------------------------------
+ * 2 = Stacked Frame | 0x0: Left view is on top and
+ * | right view on bottom
+ * | (others reserved)
+ * ------------------------------------------------------------
+ * 3 = Pixel Interleaved | 0x0: horiz interleaved, right
+ * | view pixels on even lines
+ * | 0x1: horiz interleaved, right
+ * | view pixels on odd lines
+ * | 0x2: checker board, start with
+ * | left view pixel
+ * | 0x3: vertical interleaved,
+ * | start w/ left view pixels
+ * | 0x4: vertical interleaved,
+ * | start w/ right view pixels
+ * | (others reserved)
+ * ------------------------------------------------------------
+ * 4 = Side-by-side | 0x0: left half represents left
+ * | eye view
+ * | 0x1: left half represents right
+ * | eye view
+ * ==========================================================*/
+
+ switch (format) {
+ case TIMING_3D_FORMAT_HW_FRAME_PACKING:
+ case TIMING_3D_FORMAT_SW_FRAME_PACKING:
+ /* Stacked Frame */
+ info_packet->sb[0] = 0x02;
+ info_packet->valid = true;
+ break;
+
+ case TIMING_3D_FORMAT_DP_HDMI_INBAND_FA:
+ case TIMING_3D_FORMAT_INBAND_FA:
+ /* Frame/Field Sequential,
+ * L + R view indication based on MISC1 bit 2:1 */
+ info_packet->sb[0] = 0x01;
+ info_packet->valid = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/*
+ * dal_ds_dispatch_setup_info_frame
+ *
+ * @brief
+ * Set up info frames
+ *
+ * @param
+ * path_mode *mode - [in] path mode
+ * hw_path_mode *hw_mode - [out] HW path mode whose info frame would be set
+ *
+ * @return
+ * void
+ */
+void dal_ds_dispatch_setup_info_frame(struct ds_dispatch *ds_dispatch,
+ const struct path_mode *mode, struct hw_path_mode *hw_mode)
+{
+ enum signal_type signal = SIGNAL_TYPE_NONE;
+
+ /* default all packets to invalid */
+ hw_mode->info_frame.avi_info_packet.valid = false;
+ hw_mode->info_frame.gamut_packet.valid = false;
+ hw_mode->info_frame.vendor_info_packet.valid = false;
+ hw_mode->info_frame.spd_packet.valid = false;
+ hw_mode->info_frame.vsc_packet.valid = false;
+
+ signal = dal_display_path_get_config_signal(hw_mode->display_path,
+ SINK_LINK_INDEX);
+
+ /* HDMi and DP have different info packets*/
+ if (dal_is_hdmi_signal(signal)) {
+ prepare_avi_info_frame(ds_dispatch, mode, hw_mode->display_path,
+ hw_mode->mode.overscan,
+ hw_mode->mode.underscan_rule,
+ &hw_mode->info_frame.avi_info_packet);
+ prepare_vendor_info_packet(mode,
+ &hw_mode->info_frame.vendor_info_packet);
+ prepare_default_gamut_packet(ds_dispatch, mode,
+ &hw_mode->info_frame.gamut_packet);
+ } else if (dal_is_dp_signal(signal))
+ prepare_video_stream_configuration_packet(ds_dispatch,
+ mode,
+ &hw_mode->info_frame.vsc_packet);
+}
diff --git a/drivers/gpu/drm/amd/dal/display_service/ds_dispatch_mode_setting.c b/drivers/gpu/drm/amd/dal/display_service/ds_dispatch_mode_setting.c
new file mode 100644
index 000000000000..709587820b6c
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/ds_dispatch_mode_setting.c
@@ -0,0 +1,2609 @@
+/*
+ * Copyright 2015 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 */
+#include "dal_services.h"
+
+#include "include/set_mode_interface.h"
+#include "include/hw_sequencer_interface.h"
+#include "include/hw_path_mode_set_interface.h"
+#include "include/display_path_interface.h"
+#include "include/topology_mgr_interface.h"
+#include "include/dcs_interface.h"
+#include "include/link_service_interface.h"
+#include "include/mode_query_interface.h"
+#include "include/logger_interface.h"
+#include "include/adjustment_interface.h"
+#include "include/hw_adjustment_set.h"
+
+#include "ds_dispatch.h"
+#include "ds_calculation.h"
+#include "grph_colors_group.h"
+#include "path_mode_set_with_data.h"
+
+/******************************************************************************
+ * Local constants.
+ *****************************************************************************/
+static const uint32_t DVI_10BIT_THRESHOLD_RATE_IN_KHZ = 50000;
+
+
+/******************************************************************************
+ * Local functions prototypes.
+ *****************************************************************************/
+
+/* Initialise DS dispatch */
+static bool ds_dispatch_construct(
+ struct ds_dispatch *ds,
+ const struct ds_dispatch_init_data *data);
+
+/* Build HW path mode from path mode */
+static bool build_hw_path_mode(
+ struct ds_dispatch *ds,
+ const struct path_mode *const mode,
+ struct hw_path_mode *const hw_mode,
+ enum build_path_set_reason reason,
+ struct adjustment_params *params);
+
+/* Program HW layer through HWSS */
+static bool program_hw(
+ struct ds_dispatch *ds,
+ bool enable_display);
+
+/* Update notification and flags after set mode */
+static void post_mode_change_update(
+ struct ds_dispatch *ds);
+
+/* Disable output */
+static void disable_output(
+ struct ds_dispatch *ds,
+ struct hw_path_mode_set *hw_mode_set);
+
+/* Enable output */
+static void enable_output(
+ struct ds_dispatch *ds,
+ struct hw_path_mode_set *hw_mode_set);
+
+/* Convert path mode into HW path mode */
+static void hw_mode_info_from_path_mode(
+ const struct ds_dispatch *ds_dispatch,
+ struct hw_mode_info *info,
+ struct display_path *disp_path,
+ const struct path_mode *mode,
+ enum build_path_set_reason reason);
+
+/* Tune up timing */
+static void tune_up_timing(
+ struct ds_dispatch *ds,
+ struct display_path *display_path,
+ struct hw_path_mode *hw_mode);
+
+/* Build a set of adjustments */
+static bool build_adjustment_set(
+ struct ds_dispatch *ds,
+ struct hw_path_mode *hw_mode,
+ const struct path_mode *mode,
+ struct display_path *display_path,
+ enum build_path_set_reason reason);
+
+/* Set up additional parameters for HW path mode */
+static void setup_additional_parameters(
+ const struct path_mode *mode,
+ struct hw_path_mode *hw_mode);
+
+/* Set dithering */
+static void set_dithering_options(
+ const struct ds_dispatch *ds_dispatch,
+ struct hw_mode_info *info,
+ const struct path_mode *mode,
+ struct display_path *disp_path);
+
+/* Helper to convert path mode into hw path mode */
+static void convert_mode_info(
+ const struct ds_dispatch *ds_dispatch,
+ struct hw_mode_info *info,
+ struct display_path *disp_path,
+ const struct path_mode *mode,
+ enum build_path_set_reason reason);
+
+static enum timing_3d_format get_active_timing_3d_format(
+ enum timing_3d_format timing_3d_format,
+ enum view_3d_format view_3d_format);
+
+/* Convert CRTC timing into HW format */
+static void hw_crtc_timing_from_crtc_timing(
+ struct hw_crtc_timing *hw_timing,
+ const struct crtc_timing *timing,
+ enum view_3d_format view_3d_format,
+ enum signal_type signal);
+
+/* Setup HW stereo mixer parameters */
+static void setup_hw_stereo_mixer_params(
+ struct hw_mode_info *info,
+ const struct crtc_timing *timing,
+ enum view_3d_format view_3d_format);
+
+static enum view_3d_format timing_3d_format_to_view_3d_format(
+ enum timing_3d_format timing_3d_format);
+
+static bool validate_stereo_3d_format(
+ struct display_path *display_path,
+ const struct crtc_timing *crtc_timing,
+ enum view_3d_format view_3d_format);
+
+static void enable_gtc_embedding(
+ struct ds_dispatch *ds_dispatch,
+ struct hw_path_mode_set *hw_mode_set);
+
+static void destroy_adjustment_set(
+ struct hw_adjustment_set **set);
+
+static void send_wireless_setmode_end_event(
+ struct ds_dispatch *ds_dispatch,
+ const struct path_mode_set *path_mode_set);
+/******************************************************************************
+ * Public function implementation.
+ *****************************************************************************/
+
+/* Perform static validation of Mode for this path (without taking into
+ * account other active displays).
+ * Static means considering only capabilities of Links and GOs on the path
+ * (no video memory bandwidth calculations).
+ * The functions is used to filter out modes which this path can't support. */
+bool dal_ds_dispatch_is_valid_mode_timing_for_display(
+ const struct ds_dispatch *ds_dispatch,
+ uint32_t display_path_index,
+ enum validation_method method,
+ const struct mode_timing *mode_timing)
+{
+ struct hw_path_mode hw_path_mode = { 0 };
+ struct link_validation_flags flags = { 0 };
+
+ struct display_path *display_path;
+
+ enum view_3d_format view_3d_format;
+ enum signal_type asic_signal;
+
+ bool result = true;
+
+ if (!mode_timing) {
+ dal_logger_write(ds_dispatch->dal_context->logger,
+ LOG_MAJOR_WARNING,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "%s: Invalid Input\n", __func__);
+ return false;
+ }
+
+ /* Validate mandatory pixel encoding */
+
+ if (mode_timing->crtc_timing.pixel_encoding ==
+ PIXEL_ENCODING_UNDEFINED) {
+ dal_logger_write(ds_dispatch->dal_context->logger,
+ LOG_MAJOR_WARNING,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "%s: Pixel Encoding is not defined\n",
+ __func__);
+ return false;
+ }
+
+ /* Validate mandatory color depth */
+
+ if (mode_timing->crtc_timing.display_color_depth ==
+ DISPLAY_COLOR_DEPTH_UNDEFINED) {
+ dal_logger_write(ds_dispatch->dal_context->logger,
+ LOG_MAJOR_WARNING,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "%s: Color Depth is not defined\n", __func__);
+ return false;
+ }
+
+ /* Choose action based on validation method */
+
+ switch (method) {
+ case VALIDATION_METHOD_STATIC:
+ hw_path_mode.action = HW_PATH_ACTION_STATIC_VALIDATE;
+ break;
+ case VALIDATION_METHOD_DYNAMIC:
+ hw_path_mode.action = HW_PATH_ACTION_EXISTING;
+ flags.DYNAMIC_VALIDATION = 1;
+ break;
+ default:
+ dal_logger_write(ds_dispatch->dal_context->logger,
+ LOG_MAJOR_WARNING,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "%s: Invalid Validation Method\n", __func__);
+ return false;
+ }
+
+ /* Fill up the rest of data, and do validation */
+
+ display_path = dal_tm_create_resource_context_for_display_index(
+ ds_dispatch->tm, display_path_index);
+
+ if (!display_path) {
+ dal_logger_write(ds_dispatch->dal_context->logger,
+ LOG_MAJOR_WARNING,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "%s: Failed to create temporary clone path!\n",
+ __func__);
+ return false;
+ }
+
+ hw_path_mode.display_path = display_path;
+ hw_path_mode.mode.scaling_info.src.width =
+ mode_timing->mode_info.pixel_width;
+ hw_path_mode.mode.scaling_info.src.height =
+ mode_timing->mode_info.pixel_height;
+ hw_path_mode.mode.scaling_info.dst.width =
+ mode_timing->crtc_timing.h_addressable;
+ hw_path_mode.mode.scaling_info.dst.height =
+ mode_timing->crtc_timing.v_addressable;
+ hw_path_mode.mode.refresh_rate =
+ mode_timing->mode_info.field_rate;
+
+ /* This is validation out of "display view" context.
+ * Therefore we assume 3D view_3d_format from timing only */
+
+ view_3d_format = timing_3d_format_to_view_3d_format(
+ mode_timing->crtc_timing.timing_3d_format);
+
+ asic_signal = dal_display_path_get_query_signal(
+ display_path, ASIC_LINK_INDEX);
+
+ hw_crtc_timing_from_crtc_timing(
+ &hw_path_mode.mode.timing,
+ &mode_timing->crtc_timing,
+ view_3d_format,
+ asic_signal);
+
+ setup_hw_stereo_mixer_params(
+ &hw_path_mode.mode,
+ &mode_timing->crtc_timing,
+ view_3d_format);
+
+ if (result) {
+ result = validate_stereo_3d_format(
+ display_path,
+ &mode_timing->crtc_timing,
+ view_3d_format);
+ }
+
+ /* Validate the static capabilities of this pathmode */
+
+ result = result && (HWSS_RESULT_OK ==
+ dal_hw_sequencer_validate_display_path_mode(
+ ds_dispatch->hwss, &hw_path_mode));
+
+ /* Bandwidth validation on each LINK (not to confuse with
+ * Video Memory Bandwidth validation, which is done on a SET of
+ * path modes when cofunctionality is validated). */
+
+ if (result) {
+ uint32_t link_count =
+ dal_display_path_get_number_of_links(display_path);
+
+ uint32_t i;
+
+ /* TEMPORARY CHECK */
+ if (!dal_display_path_get_link_query_interface(display_path, 0))
+ link_count = 0;
+
+ for (i = 0; i != link_count; ++i) {
+ struct link_service *ls =
+ dal_display_path_get_link_query_interface(
+ display_path, i);
+
+ if (!dal_ls_validate_mode_timing(
+ ls, display_path_index,
+ &hw_path_mode.mode.timing, flags)) {
+ result = false;
+ dal_logger_write(
+ ds_dispatch->dal_context->logger,
+ LOG_MAJOR_DISPLAY_SERVICE,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "%s: Timing validation failed in Link Service!\n",
+ __func__);
+ break;
+ }
+ }
+ }
+
+ dal_tm_destroy_resource_context_for_display_path(ds_dispatch->tm,
+ display_path);
+
+ return result;
+}
+
+void dal_ds_dispatch_pin_active_path_modes(
+ struct ds_dispatch *ds_dispatch,
+ void *param,
+ uint32_t display_index,
+ void (*func)(void *, const struct path_mode *))
+{
+ uint32_t i;
+ uint32_t count;
+ const struct path_mode *existing_mode;
+
+ dal_memset(ds_dispatch->path_modes, 0, sizeof(ds_dispatch->path_modes));
+
+ count = dal_pms_with_data_get_path_mode_num(ds_dispatch->set);
+
+ /* Step 1. Copy all existing modes into the validation list, except
+ * passed display_path index
+ */
+ for (i = 0; i < count; i++) {
+ existing_mode =
+ dal_pms_with_data_get_path_mode_at_index(
+ ds_dispatch->set, i);
+ if (existing_mode->display_path_index == display_index)
+ continue;
+ func(param, existing_mode);
+ }
+}
+
+static struct rect get_viewport(
+ struct rect *src_rect,
+ struct rect *clip_rect,
+ struct rect *dest_rect)
+{
+ struct rect viewport = {0};
+
+ viewport.x = src_rect->x + (clip_rect->x - dest_rect->x) *
+ src_rect->width / dest_rect->width;
+ viewport.width = clip_rect->width * src_rect->width / dest_rect->width;
+ viewport.y = src_rect->y + (clip_rect->y - dest_rect->y) *
+ src_rect->height / dest_rect->height;
+ viewport.height =
+ clip_rect->height * src_rect->height / dest_rect->height;
+
+ return viewport;
+}
+
+static struct overscan_info get_overscan(
+ const struct view *os_resolution,
+ const struct rect *clip_rect)
+{
+ struct overscan_info overscan = {0};
+
+ if (os_resolution == NULL || clip_rect == NULL)
+ return overscan;
+
+ overscan.left = clip_rect->x;
+ overscan.top = clip_rect->y;
+
+ overscan.right =
+ os_resolution->width - clip_rect->width - overscan.left;
+ overscan.bottom =
+ os_resolution->height - clip_rect->height - overscan.top;
+
+ if ((overscan.right + overscan.left > os_resolution->width) ||
+ (overscan.top + overscan.bottom > os_resolution->height))
+ BREAK_TO_DEBUGGER();
+
+ return overscan;
+}
+
+DAL_VECTOR_AT_INDEX(plane_configs, struct plane_config *)
+
+static void cal_scaling_overscan_params(
+ const struct path_mode *mode,
+ enum scaling_transformation scl_type,
+ struct hw_mode_info *info,
+ struct vector *plane_configs)
+{
+ uint32_t screen_w;
+ uint32_t screen_h;
+ uint32_t bound_w;
+ uint32_t bound_h;
+ uint32_t i;
+ struct view os_resolution;
+
+ uint32_t planes_num = dal_vector_get_count(plane_configs);
+
+ /*PlaneConfig used instead of PlaneAttributes since only
+ *planeConfig can be an indexable array for getBoundingClipRect
+ */
+
+ if (planes_num == 0) {
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+
+ os_resolution = mode->view;
+ screen_w = info->timing.h_addressable;
+ screen_h = info->timing.v_addressable;
+
+ /* Here we build a bounding rectangle for the destination rectangles
+ * provided by OS. As the name implies all of the destination
+ * rectangles are bound inside this rectangle. It is necessary as
+ * destination rectangles do not necessarily coincide with the
+ * display timing. The bounding rectangle is used to calculate a common
+ * scaling ratio (CSR) for all surfaces which when multiplied by scaling
+ * ration to get source rect scaled onto the dest rect will give
+ * us the true scaling ratio. This is done in a single step so no actual
+ * CSR is calculated.
+ */
+
+ bound_w = os_resolution.width;
+ bound_h = os_resolution.height;
+
+ if (bound_w == 0 || bound_h == 0) {
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+
+ /*TODO: rotation
+ * Fixed31_32 h_sr
+ * Fixed31_32 v_sr
+ *ScalingTransformation_PreserveAspectRatioScale
+ */
+ for (i = 0; i < planes_num; i++) {
+
+ struct view dest;
+ struct rect clip_rect;
+ struct rect dst_rect;
+ struct rect src_rect;
+ struct rect viewport;
+ struct overscan_info overscan;
+ struct plane_config *plane_config =
+ plane_configs_vector_at_index(plane_configs, i);
+
+ struct fixed31_32 v_sr;
+ struct fixed31_32 h_sr;
+
+ dal_memset(&clip_rect, 0, sizeof(clip_rect));
+ dal_memset(&dst_rect, 0, sizeof(dst_rect));
+ dal_memset(&src_rect, 0, sizeof(src_rect));
+
+ {
+ /* this is the else case when rotation is not enabled
+ * TODO: add rotation case above */
+
+ src_rect = plane_config->attributes.src_rect;
+ dst_rect = plane_config->attributes.dst_rect;
+ clip_rect = plane_config->attributes.clip_rect;
+ }
+
+ if (dst_rect.height == 0 || dst_rect.width == 0) {
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+
+ /**
+ * Viewport does not need to be scaled to screen resolution
+ * Underscan and destination scale with screen resolution
+ */
+ viewport = get_viewport(&src_rect, &clip_rect, &dst_rect);
+ overscan = get_overscan(&os_resolution, &clip_rect);
+
+ h_sr = dal_fixed31_32_from_int(src_rect.width);
+ v_sr = dal_fixed31_32_from_int(src_rect.height);
+
+ /* TODO: add stereo 3d h_sr and v_sr translation */
+
+ if (scl_type == SCALING_TRANSFORMATION_FULL_SCREEN_SCALE) {
+ overscan.left = overscan.left * screen_w / bound_w;
+ overscan.right = overscan.right * screen_w / bound_w;
+ /*h_sr *= screen_w;
+ h_sr /= bound_w;*/
+ overscan.top = overscan.top * screen_h / bound_h;
+ overscan.bottom = overscan.bottom * screen_h / bound_h;
+ /*v_sr *= screen_h;
+ v_sr /= bound_h;*/
+
+ /*The way scaling calculation works here is by
+ * calculating overscan Whatever remains is the timing
+ * destination
+ */
+ dest.width =
+ screen_w - overscan.left - overscan.right;
+ dest.height =
+ screen_h - overscan.top - overscan.bottom;
+ } else if (scl_type ==
+ SCALING_TRANSFORMATION_PRESERVE_ASPECT_RATIO_SCALE) {
+ /* To preserve aspect ratio without cutting parts of the
+ * surface we must use a common scaling ratio for both
+ * width and height. This ratio is the largest of the
+ * two.
+ */
+ if (screen_w * bound_h < screen_h * bound_w) {
+ /* width needs less upscaling/more downscaling
+ */
+ overscan.left = overscan.left * screen_w
+ / bound_w;
+ overscan.right = overscan.right * screen_w
+ / bound_w;
+ /* Uf = Ui*SR + (timingH - bound_h/SR)/2 where
+ * SR is ratio: bound_w/timingW */
+ overscan.top =
+ (2 * overscan.top * screen_w +
+ screen_h * bound_w -
+ bound_h * screen_w) /
+ bound_w / 2;
+ overscan.bottom =
+ (2 * overscan.bottom * screen_w +
+ screen_h * bound_w -
+ bound_h * screen_w) /
+ bound_w / 2;
+
+ h_sr = dal_fixed31_32_mul_int(h_sr, bound_w);
+ h_sr = dal_fixed31_32_div_int(h_sr, screen_w);
+ v_sr = dal_fixed31_32_mul_int(v_sr, bound_w);
+ v_sr = dal_fixed31_32_div_int(v_sr, screen_w);
+ } else {
+ /* height needs less upscaling/more downscaling
+ */
+ overscan.top = overscan.top * screen_h
+ / bound_h;
+ overscan.bottom = overscan.bottom * screen_h
+ / bound_h;
+
+ /* Uf = Ui*SR + (timingW - bound_w/SR)/2 where
+ * SR is ratio: bound_h/timingH */
+ overscan.left =
+ (2 * overscan.left * screen_h +
+ screen_w * bound_h -
+ bound_w * screen_h) /
+ bound_h / 2;
+ overscan.right =
+ (2 * overscan.right * screen_h +
+ screen_w * bound_h -
+ bound_w * screen_h) /
+ bound_h / 2;
+
+ h_sr = dal_fixed31_32_mul_int(h_sr, bound_h);
+ h_sr = dal_fixed31_32_div_int(h_sr, screen_h);
+ v_sr = dal_fixed31_32_mul_int(v_sr, bound_h);
+ v_sr = dal_fixed31_32_div_int(v_sr, screen_h);
+ }
+
+ dest.width = screen_w - overscan.left - overscan.right;
+ dest.height = screen_h - overscan.top - overscan.bottom;
+ } else if (scl_type == SCALING_TRANSFORMATION_CENTER_TIMING) {
+ /*All we do in this case is calculate how much more
+ * overscan is needed to center the bounding rectangle
+ */
+ ASSERT((screen_w >= bound_w) && (screen_h >= bound_h));
+
+ overscan.left += (screen_w - bound_w) / 2;
+ overscan.right +=
+ screen_w - bound_w - (screen_w - bound_w) / 2;
+ overscan.top += (screen_h - bound_h) / 2;
+ overscan.bottom +=
+ screen_h - bound_h - (screen_h - bound_h) / 2;
+
+ dest.width =
+ plane_config->attributes.clip_rect.width;
+ dest.height =
+ plane_config->attributes.clip_rect.height;
+ } else if (scl_type == SCALING_TRANSFORMATION_IDENTITY) {
+ /*do nothing for identity*/
+ dest.width =
+ plane_config->attributes.clip_rect.width;
+ dest.height =
+ plane_config->attributes.clip_rect.height;
+ } else {
+ /*error unsupported scalingTransformation*/
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+
+ /* Division last to minimize truncation error */
+ h_sr = dal_fixed31_32_div_int(h_sr, dst_rect.width);
+ v_sr = dal_fixed31_32_div_int(v_sr, dst_rect.height);
+
+ /*Add timing overscan to finalize overscan calculation*/
+ overscan.left += info->timing.h_overscan_left;
+ overscan.right += info->timing.h_overscan_right;
+ overscan.top += info->timing.v_overscan_top;
+ overscan.bottom += info->timing.v_overscan_bottom;
+
+ if (dest.height == 0 || dest.width == 0)
+ BREAK_TO_DEBUGGER();
+
+ plane_config->mp_scaling_data.overscan = overscan;
+
+ if (plane_config->mp_scaling_data.viewport.x == 0 &&
+ plane_config->mp_scaling_data.viewport.y == 0 &&
+ plane_config->mp_scaling_data.viewport.width == 0 &&
+ plane_config->mp_scaling_data.viewport.height == 0)
+ plane_config->mp_scaling_data.viewport = viewport;
+
+ plane_config->mp_scaling_data.dst_res = dest;
+ plane_config->mp_scaling_data.ratios.horz = h_sr;
+ plane_config->mp_scaling_data.ratios.vert = v_sr;
+ plane_config->mp_scaling_data.ratios.horz_c = h_sr;
+ plane_config->mp_scaling_data.ratios.vert_c = v_sr;
+
+ /* TODO: add MPO horzc and vertc preparation w amd w/o rotation
+ */
+
+ /* DM always passes requested num of taps even if
+ * scaling is not required
+ */
+ if (viewport.width == dest.width
+ && viewport.height == dest.height) {
+ plane_config->attributes.scaling_quality.
+ h_taps = 1;
+ plane_config->attributes.scaling_quality.
+ v_taps = 1;
+ }
+
+ if (viewport.width == 2 * dest.width
+ && (plane_config->config.dal_pixel_format ==
+ PIXEL_FORMAT_420BPP12
+ || plane_config->config.rotation ==
+ PLANE_ROTATION_ANGLE_90
+ || plane_config->config.rotation ==
+ PLANE_ROTATION_ANGLE_270))
+ plane_config->attributes.scaling_quality.h_taps_c = 1;
+
+ if (viewport.height == 2 * dest.height &&
+ (plane_config->config.dal_pixel_format ==
+ PIXEL_FORMAT_420BPP12 ||
+ plane_config->config.rotation ==
+ PLANE_ROTATION_ANGLE_0 ||
+ plane_config->config.rotation ==
+ PLANE_ROTATION_ANGLE_180))
+ plane_config->attributes.scaling_quality.
+ v_taps_c = 1;
+
+
+ /*Graphics don't need to match mmd scaling*/
+ if (plane_config->config.dal_pixel_format <=
+ PIXEL_FORMAT_GRPH_END) {
+ plane_config->attributes.scaling_quality.
+ h_taps = TAP_VALUE_INVALID;
+ plane_config->attributes.scaling_quality.v_taps =
+ TAP_VALUE_INVALID;
+ plane_config->attributes.scaling_quality.h_taps_c =
+ TAP_VALUE_INVALID;
+ plane_config->attributes.scaling_quality.v_taps_c =
+ TAP_VALUE_INVALID;
+ }
+ }
+}
+
+/*build scaler overscan parameters for new_mode*/
+static void build_scaling_params(
+ const struct ds_dispatch *ds,
+ const struct path_mode *mode,
+ enum scaling_transformation scl_type,
+ struct hw_mode_info *info)
+{
+ struct display_path *disp_path = NULL;
+ struct vector *plane_configs = NULL;
+
+ disp_path = dal_tm_display_index_to_display_path(
+ ds->tm, mode->display_path_index);
+
+ plane_configs =
+ dal_pms_with_data_get_plane_configs(
+ ds->set,
+ mode->display_path_index);
+
+ cal_scaling_overscan_params(
+ mode,
+ scl_type,
+ info,
+ plane_configs);
+}
+
+static bool is_timing_change_required(
+ const struct path_mode *existing_mode,
+ const struct path_mode *new_mode)
+{
+ struct mode_timing old_mt = *existing_mode->mode_timing;
+ struct mode_timing new_mt = *new_mode->mode_timing;
+
+ /*
+ * TODO: (see DAL2's DSDispatch::isTimingChangeRequired for reference)
+ * - stutter mode
+ * - Stereo 3D format
+ */
+
+ /* pixel format change affect FMT and color space, not timing */
+ old_mt.crtc_timing.pixel_encoding = PIXEL_ENCODING_UNDEFINED;
+ new_mt.crtc_timing.pixel_encoding = PIXEL_ENCODING_UNDEFINED;
+
+ /* ignore timing standard if all fields are equal */
+ old_mt.crtc_timing.timing_standard = TIMING_STANDARD_UNDEFINED;
+ new_mt.crtc_timing.timing_standard = TIMING_STANDARD_UNDEFINED;
+
+ /* TODO - we ignore stereo 3D until we implement it */
+ old_mt.crtc_timing.timing_3d_format = TIMING_3D_FORMAT_NONE;
+ new_mt.crtc_timing.timing_3d_format = TIMING_3D_FORMAT_NONE;
+
+ /* ignore vic and hdmi_vic */
+ old_mt.crtc_timing.vic = 0;
+ new_mt.crtc_timing.vic = 0;
+
+ old_mt.crtc_timing.hdmi_vic = 0;
+ new_mt.crtc_timing.hdmi_vic = 0;
+
+ /* compare pixel clock within 10kHz */
+ old_mt.crtc_timing.pix_clk_khz /= 10;
+ new_mt.crtc_timing.pix_clk_khz /= 10;
+
+
+ if (dal_memcmp(&old_mt, &new_mt, sizeof(struct mode_timing)))
+ return true;
+
+ /* TODO check if adjusted HW mode timing changed */
+
+ return false;
+}
+
+/*
+ * dal_set_mode_interface_set_mode
+ *
+ * Set mode on a set of display paths
+ */
+enum ds_return dal_ds_dispatch_set_mode(
+ struct ds_dispatch *ds_dispatch,
+ const struct path_mode_set *path_mode_set)
+{
+ enum ds_return result = DS_ERROR;
+
+ uint32_t path_mode_num;
+ uint32_t i;
+
+ if (!ds_dispatch || !path_mode_set) {
+ BREAK_TO_DEBUGGER();
+ return DS_ERROR;
+ }
+
+ if (!dal_tm_is_hw_state_valid(ds_dispatch->tm)) {
+ /* TODO: optimize display programming */
+
+ /* HW transition from VBIOS-controlled to driver */
+ dal_tm_enable_accelerated_mode(ds_dispatch->tm);
+ }
+
+ path_mode_num = dal_pms_get_path_mode_num(path_mode_set);
+
+ /* TODO: Reset mode? */
+
+ for (i = 0; i < path_mode_num; i++) {
+ bool timing_changed = false;
+ bool view_res_changed = false;
+ bool new_path = false;
+ bool path_acquired = false;
+ /* TODO bool audio_bandwidth_changed = true;*/
+
+ const struct path_mode *mode =
+ dal_pms_get_path_mode_at_index(path_mode_set, i);
+
+ uint32_t disp_index = mode->display_path_index;
+
+ const struct path_mode *existing_mode =
+ dal_pms_with_data_get_path_mode_for_display_index(
+ ds_dispatch->set, disp_index);
+
+ struct active_path_data *existing_data =
+ dal_pms_with_data_get_path_data_for_display_index(
+ ds_dispatch->set, disp_index);
+
+
+ struct active_path_data data_copy;
+
+ /* Copy existing path data */
+ if (existing_data) {
+ dal_memmove(&data_copy, existing_data,
+ sizeof(struct active_path_data));
+
+ existing_data = &data_copy;
+ }
+
+ /* TODO : fight -Wframe-larger-than caused by
+ * too large struct hw_path_mode allocated on stack
+ if (existing_mode) {
+ struct hw_path_mode old = { 0 };
+ struct hw_path_mode new = { 0 };
+
+ build_hw_path_mode(
+ ds_dispatch, existing_mode, &old,
+ BUILD_PATH_SET_REASON_GET_ACTIVE_PATHS, NULL);
+
+ build_hw_path_mode(
+ ds_dispatch, new_mode, &new,
+ BUILD_PATH_SET_REASON_GET_ACTIVE_PATHS, NULL);
+
+ audio_bandwidth_changed =
+ dal_hw_sequencer_has_audio_bandwidth_changed(
+ ds_dispatch->hwss, &old, &new);
+ }*/
+
+ /* TODO: Handle gamut pack change*/
+
+ /* TODO: Handle stereo 3D change*/
+
+ /* Update existing path mode */
+ if (existing_mode) {
+ /* TODO: Handle flags for existing path*/
+
+ if (is_timing_change_required(
+ existing_mode, mode))
+ timing_changed = true;
+
+ if (existing_mode->view.height != mode->view.height ||
+ existing_mode->view.width != mode->view.width)
+ view_res_changed = true;
+
+ /* remove existing path */
+ dal_pms_with_data_remove_path_mode_for_display_index(
+ ds_dispatch->set, disp_index);
+ } else {
+ /* Enabling new path */
+ path_acquired =
+ dal_tm_acquire_display_path(
+ ds_dispatch->tm, disp_index);
+
+ if (!path_acquired) {
+ BREAK_TO_DEBUGGER();
+ continue;
+ }
+
+ timing_changed = true;
+ view_res_changed = true;
+ new_path = true;
+ }
+
+ /* Add the path mode to the current active path mode set*/
+ if (dal_pms_with_data_add_path_mode_with_data(
+ ds_dispatch->set, mode, existing_data))
+ result = DS_SUCCESS;
+ else
+ BREAK_TO_DEBUGGER();
+
+ {
+ struct plane_config pc;
+
+ dal_memset(&pc, 0, sizeof(pc));
+
+ pc.attributes.dst_rect.height = mode->view.height;
+ pc.attributes.dst_rect.width = mode->view.width;
+ pc.attributes.dst_rect.x = 0;
+ pc.attributes.dst_rect.y = 0;
+ pc.attributes.clip_rect = pc.attributes.dst_rect;
+ pc.attributes.src_rect = pc.attributes.dst_rect;
+
+ /* TODO: add stereo 3d translation here */
+ dal_pms_with_data_add_plane_configs(
+ ds_dispatch->set,
+ mode->display_path_index,
+ &pc,
+ 1);
+ }
+
+ /* Setup active data flags for pre-mode change*/
+ if (result == DS_SUCCESS) {
+ struct active_path_data *data =
+ dal_pms_with_data_get_path_data_for_display_index(
+ ds_dispatch->set, disp_index);
+
+ data->flags.all = 0;
+ data->flags.bits.ENABLE_HW = new_path;
+ data->flags.bits.REPROGRAM_HW = !new_path;
+ data->flags.bits.SYNC_TIMING_SERVER = (i == 0);
+ data->flags.bits.POST_ACTION_DISPLAY_ON = true;
+ data->flags.bits.TIMING_CHANGED = timing_changed;
+ data->flags.bits.VIEW_RES_CHANGED = view_res_changed;
+
+ /* TODO: use real value */
+ data->flags.bits.PENDING_DISPLAY_STEREO = false;
+ data->flags.bits.PIXEL_ENCODING_CHANGED = false;
+ data->flags.bits.GAMUT_CHANGED = false;
+ data->flags.bits.AUDIO_BANDWIDTH_CHANGED = false;
+
+ /* TODO: adjustment */
+ /*build scaler overscan parameters for new_mode,
+ * plane_configs is not added yet*/
+ /*build_scaler_overscan_params(ds_dispatch, mode);*/
+ }
+ }
+
+ /* Program HW*/
+ if (result == DS_SUCCESS) {
+ bool enable_display =
+ !dal_pms_is_display_power_off_required(path_mode_set);
+
+ result = (program_hw(ds_dispatch, enable_display)
+ ? DS_SUCCESS : DS_ERROR);
+ }
+
+ if (result == DS_SUCCESS) {
+ /* TODO: Post-set mode for 3D, overlay, and embedded */
+ send_wireless_setmode_end_event(ds_dispatch, path_mode_set);
+
+ }
+ /* Post-set mode. Update notification and data flags */
+ post_mode_change_update(ds_dispatch);
+
+ return result;
+}
+
+/*
+ * dal_ds_dispatch_build_hw_path_mode_for_adjustment
+ *
+ * Create HW path mode specifically for adjustment or generic control request
+ * on an active display
+ */
+bool dal_ds_dispatch_build_hw_path_mode_for_adjustment(
+ struct ds_dispatch *ds_dispatch,
+ struct hw_path_mode *mode,
+ uint32_t disp_index,
+ struct adjustment_params *params)
+{
+ const struct path_mode *path_mode =
+ dal_pms_with_data_get_path_mode_for_display_index(
+ ds_dispatch->set, disp_index);
+
+ if (mode != NULL && path_mode != NULL)
+ return build_hw_path_mode(
+ ds_dispatch,
+ path_mode,
+ mode,
+ BUILD_PATH_SET_REASON_SET_ADJUSTMENT,
+ params);
+
+ return false;
+
+}
+
+bool dal_ds_dispatch_build_hw_path_set_for_adjustment(
+ struct ds_dispatch *ds,
+ struct hw_path_mode_set *hw_pms,
+ struct adjustment_params *params)
+{
+
+ uint32_t path_num = dal_pms_with_data_get_path_mode_num(ds->set);
+
+ if (hw_pms != NULL)
+ return dal_ds_dispatch_build_hw_path_set(
+ ds,
+ path_num,
+ dal_pms_with_data_get_path_mode_at_index(ds->set, 0),
+ hw_pms,
+ BUILD_PATH_SET_REASON_SET_ADJUSTMENT,
+ params);
+ return false;
+
+}
+
+/*
+ * dal_ds_dispatch_create
+ *
+ * Create DS dispatch
+ */
+struct ds_dispatch *dal_ds_dispatch_create(
+ const struct ds_dispatch_init_data *data)
+{
+ struct ds_dispatch *ds_dispatch =
+ dal_alloc(sizeof(struct ds_dispatch));
+
+ if (!ds_dispatch) {
+ BREAK_TO_DEBUGGER();
+ return NULL;
+ }
+
+ if (ds_dispatch_construct(ds_dispatch, data))
+ return ds_dispatch;
+
+ BREAK_TO_DEBUGGER();
+
+ dal_free(ds_dispatch);
+
+ return NULL;
+}
+
+static void destruct(struct ds_dispatch *ds_dispatch)
+{
+ dal_pms_with_data_destroy(&ds_dispatch->set);
+}
+
+/*
+ * dal_ds_dispatch_destroy
+ *
+ * Destroy DS dispatch
+ */
+void dal_ds_dispatch_destroy(
+ struct ds_dispatch **ds_dispatch)
+{
+ if (!ds_dispatch || !*ds_dispatch) {
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+
+ destruct(*ds_dispatch);
+
+ dal_free(*ds_dispatch);
+
+ *ds_dispatch = NULL;
+}
+
+struct set_mode_params *dal_ds_dispatch_create_resource_context(
+ const struct ds_dispatch *ds_dispatch,
+ const uint32_t display_idx[],
+ uint32_t idx_num)
+{
+ struct set_mode_params *sm_params;
+ struct set_mode_params_init_data init_data;
+
+ init_data.hws = ds_dispatch->hwss;
+ init_data.ctx = ds_dispatch->dal_context;
+ init_data.tm = ds_dispatch->tm;
+
+ sm_params = dal_set_mode_params_create(&init_data);
+ if (!sm_params)
+ return NULL;
+
+ if (dal_set_mode_params_init_with_topology(
+ sm_params,
+ display_idx,
+ idx_num))
+ return sm_params;
+
+ dal_set_mode_params_destroy(&sm_params);
+ return NULL;
+}
+
+/*
+* do_reset_mode
+*
+* Reset mode on a set of display paths to make the paths be properly released
+*
+* If successful, returns DS_SUCCESS. Any other value indicates a failure.
+*/
+enum ds_return do_reset_mode(
+ struct ds_dispatch *ds_dispatch,
+ const uint32_t displays_num,
+ const uint32_t *display_index,
+ bool bypass_reset_vcc)
+{
+ enum ds_return ret = DS_SUCCESS;
+ bool do_hw_programming = false;
+ uint32_t i;
+
+ if (displays_num == 0)
+ return ret;
+
+ /* TODO: Reset workstation stereo */
+
+ for (i = 0; i < displays_num; i++) {
+ uint32_t index = display_index[i];
+ const struct path_mode *path_mode =
+ dal_pms_with_data_get_path_mode_for_display_index(
+ ds_dispatch->set,
+ index);
+ struct active_path_data *path_data =
+ dal_pms_with_data_get_path_data_for_display_index(
+ ds_dispatch->set,
+ index);
+
+ /* If we have at least one PathMode to reset - this loop
+ * considered successful and we will reprogram HW for relevant
+ * paths. */
+ if (path_mode != NULL) {
+ if (path_data != NULL) {
+ /* save the AUDIO_BANDWIDTH_CHANGED value which
+ * could have been set to true in reset_mode
+ * this also serves to reset the
+ * DISPLAY_PATH_INVALID flag
+ */
+ bool audio_bandwidth_changed =
+ path_data->flags.bits.
+ AUDIO_BANDWIDTH_CHANGED;
+ path_data->flags.all = 0;
+ path_data->flags.bits.DISABLE_HW = true;
+ path_data->flags.bits.KEEP_VCC_ON_DISABLE_HW =
+ bypass_reset_vcc;
+ path_data->flags.bits.AUDIO_BANDWIDTH_CHANGED =
+ audio_bandwidth_changed;
+ }
+
+ /* TODO: Reset synchronization state whatever it was -
+ * since we are going to reprogram this display path
+ * TODO: Reset display stereo */
+ do_hw_programming = true;
+ }
+ }
+
+ if (do_hw_programming)
+ ret = (program_hw(ds_dispatch, false) ?
+ DS_SUCCESS : DS_ERROR);
+
+ post_mode_change_update(ds_dispatch);
+
+ return ret;
+}
+
+/*
+ * dal_ds_dispatch_reset_mode
+ *
+ * Reset mode on a set of display paths to make the paths to be properly
+ * released.
+ *
+ * If successful, returns DS_SUCCESS. Any other value indicates a failure.
+ */
+enum ds_return dal_ds_dispatch_reset_mode(
+ struct ds_dispatch *ds_dispatch,
+ const uint32_t displays_num,
+ const uint32_t *display_indexes)
+{
+ enum ds_return result = DS_SUCCESS;
+
+ /* uint32_t ur_sent_num = 0;
+ * bool update_ur = false;
+ */
+ uint32_t i;
+
+ if (!ds_dispatch || !display_indexes)
+ return DS_ERROR;
+
+ /* We never want to call ResetMode before enabling accelerated mode.
+ * Doing so can power down a display path in the incorrect order,
+ * resulting in a hang in VBIOS table.
+ * The reason is because driver logic state of the display paths may not
+ * match what VBIOS has enabled.
+ * So we must always power down the hw blocks in a specific sequence.
+ */
+ if (!dal_tm_is_hw_state_valid(ds_dispatch->tm)) {
+ /* enableAcceleratedMode will do two things:
+ * 1. call TopologyManager::EnableAcceleratedMode to power down
+ * all hw blocks
+ * 2. mark all displays as invalid
+ */
+ /* TODO: accelerated mode */
+ }
+
+ /* TODO: finish implementation */
+
+ for (i = 0; i < displays_num; ++i) {
+ struct active_path_data *path_data;
+ /*struct display_path *display_path =
+ dal_tm_display_index_to_display_path(
+ ds_dispatch->tm,
+ display_indexes[i]);
+
+ struct audio *audio = dal_display_path_get_audio(
+ display_path,
+ ASIC_LINK_INDEX);
+
+ if ((audio != NULL) && (ur_sent_num == 0))
+ update_ur = true;
+ */
+ /* Disable Mirabilis and send UR once
+ * In dal_hw_sequencer_enable_audio_channel_split_mapping,
+ * there is a check that the display path has a valid audio
+ * object before attempting to send an UR to audio driver. So,
+ * we send UR on the first display path that has a valid audio
+ * object.
+ */
+ /* TODO: implement
+ dal_hw_sequencer_enable_audio_channel_split_mapping(
+ display_path, 0, false, update_ur);
+ */
+
+ path_data =
+ dal_pms_with_data_get_path_data_for_display_index(
+ ds_dispatch->set,
+ display_indexes[i]);
+
+ if (path_data)
+ path_data->flags.bits.AUDIO_BANDWIDTH_CHANGED = true;
+ }
+
+ result = do_reset_mode(
+ ds_dispatch, displays_num, display_indexes, false);
+
+ /* TODO: clear previous bandwidth validation on current mode. */
+
+ return result;
+}
+
+
+/* dal_ds_dispatch_get_active_path_mode
+ *
+ * Return active path modes
+ */
+struct path_mode_set_with_data *dal_ds_dispatch_get_active_pms_with_data(
+ struct ds_dispatch *ds_dispatch)
+{
+ return ds_dispatch->set;
+}
+
+
+enum ds_return dal_ds_dispatch_pre_adapter_clock_change(
+ struct ds_dispatch *ds)
+{
+ uint32_t path_num = dal_pms_with_data_get_path_mode_num(ds->set);
+
+ struct hw_path_mode_set *hw_mode_set = dal_hw_path_mode_set_create();
+
+ if (!hw_mode_set) {
+ BREAK_TO_DEBUGGER();
+ return DS_ERROR;
+ }
+
+ /* Convert path mode set into HW path mode set for HWSS */
+ if (!dal_ds_dispatch_build_hw_path_set(
+ ds,
+ path_num,
+ dal_pms_with_data_get_path_mode_at_index(ds->set, 0),
+ hw_mode_set,
+ BUILD_PATH_SET_REASON_WATERMARKS,
+ NULL)) {
+ return DS_ERROR;
+ }
+
+ if (dal_hw_path_mode_set_get_paths_number(hw_mode_set))
+ dal_hw_sequencer_set_safe_displaymark(ds->hwss, hw_mode_set);
+
+ dal_ds_dispatch_destroy_hw_path_set(hw_mode_set);
+
+ return DS_SUCCESS;
+}
+
+enum ds_return dal_ds_dispatch_post_adapter_clock_change(
+ struct ds_dispatch *ds)
+{
+ uint32_t path_num = dal_pms_with_data_get_path_mode_num(ds->set);
+
+ struct hw_path_mode_set *hw_mode_set = dal_hw_path_mode_set_create();
+
+ if (!hw_mode_set) {
+ BREAK_TO_DEBUGGER();
+ return DS_ERROR;
+ }
+
+ /* Convert path mode set into HW path mode set for HWSS */
+ if (!dal_ds_dispatch_build_hw_path_set(
+ ds,
+ path_num,
+ dal_pms_with_data_get_path_mode_at_index(ds->set, 0),
+ hw_mode_set,
+ BUILD_PATH_SET_REASON_WATERMARKS,
+ NULL)) {
+ return DS_ERROR;
+ }
+
+ if (dal_hw_path_mode_set_get_paths_number(hw_mode_set))
+ dal_hw_sequencer_set_displaymark(ds->hwss, hw_mode_set);
+
+ dal_ds_dispatch_destroy_hw_path_set(hw_mode_set);
+
+ return DS_SUCCESS;
+}
+
+/*
+ * Local function definition
+ */
+
+/* Initialize DS dispatch */
+static bool ds_dispatch_construct(
+ struct ds_dispatch *ds,
+ const struct ds_dispatch_init_data *data)
+{
+ if (!data) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+
+ ds->dal_context = data->dal_context;
+ ds->as = data->as;
+ ds->hwss = data->hwss;
+ ds->tm = data->tm;
+ ds->ts = data->ts;
+
+ ds->set = dal_pms_with_data_create();
+ if (!ds->set) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+ if (!dal_ds_dispatch_initialize_adjustment(ds)) {
+ dal_pms_with_data_destroy(&ds->set);
+ return false;
+ }
+ return true;
+}
+
+/*
+ * program_hw
+ *
+ * Program HW layer through HWSS.
+ */
+static bool program_hw(
+ struct ds_dispatch *ds,
+ bool enable_display)
+{
+ uint32_t path_num = dal_pms_with_data_get_path_mode_num(ds->set);
+
+ struct hw_path_mode_set *hw_mode_set = dal_hw_path_mode_set_create();
+
+ bool result = false;
+
+ if (!hw_mode_set) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+
+ /* Convert path mode set into HW path mode set for HWSS */
+ result = dal_ds_dispatch_build_hw_path_set(
+ ds,
+ path_num,
+ dal_pms_with_data_get_path_mode_at_index(ds->set, 0),
+ hw_mode_set,
+ BUILD_PATH_SET_REASON_SET_MODE,
+ NULL);
+
+ /* TODO: Apply synchronization */
+
+ /* HW programming */
+ if (result) {
+ /* Disable output*/
+ disable_output(ds, hw_mode_set);
+
+ /* Set Mode */
+ if (dal_hw_sequencer_set_mode(ds->hwss, hw_mode_set) !=
+ HWSS_RESULT_OK)
+ result = false;
+
+ /* Enable output */
+ if (enable_display)
+ enable_output(ds, hw_mode_set);
+
+ }
+
+ /* TODO: update ISR and DRR setup */
+
+ dal_ds_dispatch_destroy_hw_path_set(hw_mode_set);
+
+ return result;
+}
+
+/*
+ * dal_ds_dispatch_build_hw_path_set
+ *
+ * Build a set of HW path modes from the given paths
+ */
+bool dal_ds_dispatch_build_hw_path_set(
+ struct ds_dispatch *ds,
+ const uint32_t num,
+ const struct path_mode *const mode,
+ struct hw_path_mode_set *const hw_mode_set,
+ enum build_path_set_reason reason,
+ struct adjustment_params *params)
+{
+ bool result = true;
+
+ uint32_t adj_counter = 0;
+ uint32_t i;
+
+ if (num == 0 || !mode) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+
+ /* Build HW path mode for every path */
+ for (i = 0; i < num; i++) {
+ struct hw_path_mode hw_path_mode = { 0 };
+
+ if (!build_hw_path_mode(
+ ds, &mode[i], &hw_path_mode, reason, params)) {
+ result = false;
+ break;
+ }
+
+ if (params && params->affected_path ==
+ hw_path_mode.display_path)
+ adj_counter++;
+
+ if (reason == BUILD_PATH_SET_REASON_SET_MODE)
+ if (!dal_hw_path_mode_set_add(
+ hw_mode_set, &hw_path_mode, NULL)) {
+ result = false;
+ break;
+ }
+ }
+
+ /* Only allow one adjustment per path each time */
+ if (reason == BUILD_PATH_SET_REASON_SET_ADJUSTMENT && adj_counter > 1)
+ result = false;
+
+ /* TODO: Free all adjustment if error occurs */
+
+ if (!result) {
+ uint32_t j;
+ struct hw_path_mode *mode;
+
+ for (j = 0; j < i; j++) {
+ mode = dal_hw_path_mode_set_get_path_by_index(
+ hw_mode_set, j);
+
+ if (mode != NULL && mode->adjustment_set != NULL)
+ destroy_adjustment_set(&mode->adjustment_set);
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Builds HW Path mode with adjustments applied according to the parameters.
+ * As part of the building procedure, will apply relevant adjustments,
+ * only skipping adjustments that specified as skip_adjustments.
+ *
+ * NOTE: This function resets output parameter hw_mode.
+ *
+ * \param [in] mode: path Mode from which to build hw Path mode.
+ * \param [out] hw_mode: HW Path mode to fill.
+ * \param [in] reason: The reason for this request.
+ * \param [in] skip_adjustments: Adjustments which should NOT be applied as
+ * part of building hw Path set.
+ *
+ * \return
+ * true: HW Path mode was successfully built
+ * false: otherwise
+ */
+static bool build_hw_path_mode(
+ struct ds_dispatch *ds,
+ const struct path_mode *const mode,
+ struct hw_path_mode *const hw_mode,
+ enum build_path_set_reason reason,
+ struct adjustment_params *skip_adjustments)
+{
+ struct active_path_data *data = NULL;
+ struct display_path *disp_path = NULL;
+ bool adjustment_done = false;
+
+ disp_path = dal_tm_display_index_to_display_path(
+ ds->tm,
+ mode->display_path_index);
+
+ data = dal_pms_with_data_get_path_data_for_display_index(
+ ds->set,
+ mode->display_path_index);
+
+ /*associate hw_info->plane_configs with ds_dispatch->set->
+ *plane_configs
+ */
+ hw_mode->plane_configs =
+ dal_pms_with_data_get_plane_configs(
+ ds->set,
+ mode->display_path_index);
+
+ if (!disp_path) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+
+ /* Setup HW action flags */
+ if (data) {
+ hw_mode->action_flags.TIMING_CHANGED =
+ data->flags.bits.TIMING_CHANGED;
+ hw_mode->action_flags.PIXEL_ENCODING_CHANGED =
+ data->flags.bits.PIXEL_ENCODING_CHANGED;
+ hw_mode->action_flags.RESYNC_PATH =
+ data->flags.bits.RESYNC_HW;
+ hw_mode->action_flags.GAMUT_CHANGED =
+ data->flags.bits.GAMUT_CHANGED;
+ hw_mode->action_flags.TURN_OFF_VCC = true;
+
+ /* TODO: Do not turn off VCC as optimization*/
+
+ /* TODO: Implement viewport_adjustment
+ if (reason == BUILD_PATH_SET_REASON_SET_MODE)
+ hw_mode->mode.view_port_adjustments =
+ &data->viewport_adjustment;
+ */
+
+ if (data->flags.bits.DISABLE_HW)
+ hw_mode->action = HW_PATH_ACTION_RESET;
+ else if (data->flags.bits.ENABLE_HW ||
+ data->flags.bits.REPROGRAM_HW)
+ hw_mode->action = HW_PATH_ACTION_SET;
+ else if (data->flags.bits.EXISTING)
+ hw_mode->action = HW_PATH_ACTION_EXISTING;
+ else
+ BREAK_TO_DEBUGGER();
+
+ /* TODO: adjustment for down scaling */
+ } else {
+ ASSERT(reason == BUILD_PATH_SET_REASON_VALIDATE);
+ ASSERT(reason == BUILD_PATH_SET_REASON_FALLBACK_UNDERSCAN);
+
+ hw_mode->action = HW_PATH_ACTION_SET;
+ }
+
+ /* Setup initial HW path mode */
+ hw_mode->display_path = disp_path;
+
+ hw_mode_info_from_path_mode(
+ ds, &hw_mode->mode, disp_path, mode, reason);
+
+ setup_additional_parameters(mode, hw_mode);
+
+ if (skip_adjustments && skip_adjustments->affected_path == disp_path) {
+ switch (skip_adjustments->action) {
+ case ADJUSTMENT_ACTION_VALIDATE:
+ hw_mode->action = HW_PATH_ACTION_SET;
+ break;
+ case ADJUSTMENT_ACTION_SET_ADJUSTMENT:
+ hw_mode->action = HW_PATH_ACTION_SET_ADJUSTMENT;
+ break;
+ default:
+ break;
+ }
+
+ /* TODO: build calculated adjustments */
+ } else {
+ build_adjustment_set(ds, hw_mode, mode, disp_path, reason);
+
+ adjustment_done = true;
+ }
+
+ tune_up_timing(ds, disp_path, hw_mode);
+
+ if (data && adjustment_done)
+ dal_ds_dispatch_setup_info_frame(ds, mode, hw_mode);
+
+ return true;
+}
+
+/*
+ * dal_ds_dispatch_destroy_hw_path_set
+ *
+ * Destroy a set of HW path
+ */
+void dal_ds_dispatch_destroy_hw_path_set(
+ struct hw_path_mode_set *hw_mode_set)
+{
+ uint32_t i;
+ uint32_t num;
+ struct hw_path_mode *mode;
+
+ if (!hw_mode_set) {
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+
+ num = dal_hw_path_mode_set_get_paths_number(hw_mode_set);
+
+ for (i = 0; i < num; i++) {
+ mode = dal_hw_path_mode_set_get_path_by_index(
+ hw_mode_set, i);
+
+ if (mode != NULL && mode->adjustment_set != NULL)
+ destroy_adjustment_set(&mode->adjustment_set);
+ }
+
+ dal_hw_path_mode_set_destroy(&hw_mode_set);
+}
+
+/*
+ * disable_output
+ *
+ * Disable output
+ */
+static void disable_output(
+ struct ds_dispatch *ds,
+ struct hw_path_mode_set *hw_mode_set)
+{
+ uint32_t i;
+ uint32_t j;
+ uint32_t num = dal_pms_with_data_get_path_mode_num(ds->set);
+
+ for (i = 0; i < num; i++) {
+ struct link_service *link = NULL;
+ struct hw_path_mode *hw_mode =
+ dal_hw_path_mode_set_get_path_by_index(
+ hw_mode_set, i);
+
+ const struct path_mode *mode =
+ dal_pms_with_data_get_path_mode_at_index(ds->set, i);
+
+ struct active_path_data *data =
+ dal_pms_with_data_get_path_data_at_index(ds->set, i);
+
+ struct display_path *disp_path =
+ dal_tm_display_index_to_display_path(
+ ds->tm, mode->display_path_index);
+
+ uint32_t link_count =
+ dal_display_path_get_number_of_links(disp_path);
+
+ bool disable_required = data->flags.bits.DISABLE_HW;
+
+ bool safe_mode_change = data->flags.bits.TIMING_CHANGED;
+
+ if (!dal_display_path_is_target_powered_off(disp_path) &&
+ safe_mode_change)
+ data->flags.bits.POST_ACTION_DISPLAY_ON = true;
+
+ /* display currently disabled, don't need to disable output */
+ if (data->flags.bits.ENABLE_HW)
+ continue;
+
+ if (disable_required || safe_mode_change) {
+ for (j = link_count; j > 0; j--) {
+ enum signal_type signal;
+
+ struct link_service *link =
+ dal_display_path_get_link_config_interface(
+ disp_path, j - 1);
+
+ dal_ls_blank_stream(
+ link,
+ mode->display_path_index,
+ hw_mode);
+
+ dal_hw_sequencer_mute_audio_endpoint(
+ ds->hwss,
+ hw_mode->display_path,
+ true);
+
+ signal = dal_display_path_get_query_signal(
+ disp_path, j - 1);
+
+ if (signal == SIGNAL_TYPE_WIRELESS)
+ dal_hw_sequencer_enable_wireless_idle_detection
+ (ds->hwss, false);
+ }
+ }
+
+
+ if (disable_required) {
+ for (j = link_count; j > 0; j--) {
+ struct link_service *link =
+ dal_display_path_get_link_config_interface(
+ disp_path, j - 1);
+
+ /* TODO: Disable audio jack presence */
+
+ dal_ls_disable_stream(
+ link,
+ mode->display_path_index,
+ hw_mode);
+ }
+
+ data->display_state.OUTPUT_ENABLED = 0;
+ data->display_state.OUTPUT_BLANKED = 1;
+ } else if (safe_mode_change) {
+ for (j = link_count; j > 0; j--) {
+ struct link_service *link =
+ dal_display_path_get_link_config_interface(
+ disp_path, j - 1);
+
+ /* TODO: Disable audio jack presence */
+
+ dal_ls_pre_mode_change(
+ link,
+ mode->display_path_index,
+ hw_mode);
+ }
+
+ data->display_state.OUTPUT_BLANKED = 1;
+ }
+
+ link = dal_display_path_get_link_config_interface(
+ disp_path, ASIC_LINK_INDEX);
+
+ dal_ls_get_current_link_setting(
+ link, &hw_mode->link_settings);
+ }
+}
+
+/*
+ * enable_output
+ *
+ * Enable output
+ */
+static void enable_output(
+ struct ds_dispatch *ds,
+ struct hw_path_mode_set *hw_mode_set)
+{
+ uint32_t turned_on_displays = 0;
+
+ uint32_t i;
+ uint32_t num = dal_pms_with_data_get_path_mode_num(ds->set);
+
+ for (i = 0; i != num; ++i) {
+ struct display_path *disp_path;
+
+ uint32_t link_count;
+ uint32_t j;
+
+ struct hw_path_mode *hw_mode =
+ dal_hw_path_mode_set_get_path_by_index(
+ hw_mode_set,
+ i);
+ const struct path_mode *mode =
+ dal_pms_with_data_get_path_mode_at_index(ds->set, i);
+ struct active_path_data *data =
+ dal_pms_with_data_get_path_data_at_index(ds->set, i);
+
+ if (data->flags.bits.DISABLE_HW ||
+ !data->flags.bits.POST_ACTION_DISPLAY_ON ||
+ data->flags.bits.SKIP_ENABLE) {
+ continue;
+ }
+
+ disp_path = dal_tm_display_index_to_display_path(
+ ds->tm, mode->display_path_index);
+
+ link_count = dal_display_path_get_number_of_links(disp_path);
+
+ if (!data->display_state.OUTPUT_ENABLED) {
+ for (j = 0; j < link_count; j++) {
+ struct link_service *link =
+ dal_display_path_get_link_config_interface(
+ disp_path, j);
+
+ dal_ls_enable_stream(
+ link,
+ mode->display_path_index,
+ hw_mode);
+ }
+ } else if (data->display_state.OUTPUT_BLANKED) {
+ for (j = 0; j < link_count; j++) {
+ struct link_service *link =
+ dal_display_path_get_link_config_interface(
+ disp_path, j);
+
+ dal_ls_post_mode_change(
+ link,
+ mode->display_path_index,
+ hw_mode);
+ }
+ } else {
+ struct link_service *link =
+ dal_display_path_get_link_config_interface(
+ disp_path, ASIC_LINK_INDEX);
+
+ dal_hw_sequencer_update_info_packets(ds->hwss, hw_mode);
+
+ dal_ls_update_stream_features(link, hw_mode);
+ }
+
+ if (!data->display_state.OUTPUT_ENABLED ||
+ data->display_state.OUTPUT_BLANKED) {
+ for (j = 0; j < link_count; j++) {
+
+ struct link_service *link =
+ dal_display_path_get_link_config_interface(
+ disp_path, j);
+
+ dal_ls_unblank_stream(
+ link,
+ mode->display_path_index,
+ hw_mode);
+ }
+
+ turned_on_displays |=
+ (1 << dal_display_path_get_display_index(
+ disp_path));
+
+ data->display_state.OUTPUT_BLANKED = 0;
+ data->display_state.OUTPUT_ENABLED = 1;
+ }
+
+ data->flags.bits.POST_ACTION_DISPLAY_ON = false;
+ }
+
+ /* Enable GTC embedding on audio stream if GTC feature isn't disabled */
+ if (!dal_adapter_service_is_feature_supported(
+ FEATURE_DISABLE_DP_GTC_SYNC))
+ enable_gtc_embedding(ds, hw_mode_set);
+
+ /* After GTC enabled (or skipped if not needed)
+ * we could "hotplug" audio device */
+ for (i = 0; i != num; ++i) {
+ const struct path_mode *mode =
+ dal_pms_with_data_get_path_mode_at_index(ds->set, i);
+
+ if (turned_on_displays & (1 << mode->display_path_index))
+ dal_hw_sequencer_enable_azalia_audio_jack_presence(
+ ds->hwss,
+ dal_tm_display_index_to_display_path(
+ ds->tm, mode->display_path_index));
+ }
+
+ for (i = 0; i != num; ++i) {
+ const struct path_mode *mode =
+ dal_pms_with_data_get_path_mode_at_index(ds->set, i);
+
+ if (turned_on_displays & (1 << mode->display_path_index))
+ dal_hw_sequencer_mute_audio_endpoint(
+ ds->hwss,
+ dal_tm_display_index_to_display_path(
+ ds->tm, mode->display_path_index),
+ false);
+ }
+}
+
+/*
+ * post_mode_change_update
+ *
+ * Update notification and flags after set mode
+ */
+static void post_mode_change_update(
+ struct ds_dispatch *ds)
+{
+ uint32_t i;
+
+ for (i = dal_pms_with_data_get_path_mode_num(ds->set); i > 0; i--) {
+ struct active_path_data *data =
+ dal_pms_with_data_get_path_data_at_index(
+ ds->set, i - 1);
+
+ const struct path_mode *mode =
+ dal_pms_with_data_get_path_mode_at_index(
+ ds->set,
+ i - 1);
+
+ ASSERT(data);
+ ASSERT(mode);
+
+ if (data->flags.bits.DISABLE_HW) {
+ dal_tm_release_display_path(
+ ds->tm, mode->display_path_index);
+ dal_pms_with_data_remove_path_mode_at_index(
+ ds->set,
+ i - 1);
+ } else {
+ /* Need to restore this value after reset */
+ bool display_on =
+ data->flags.bits.POST_ACTION_DISPLAY_ON;
+
+ /* Reset flags */
+ data->flags.bits.RESYNC_HW = false;
+ data->flags.bits.SYNC_TIMING_SERVER = false;
+ data->flags.bits.NO_DEFAULT_DOWN_SCALING = false;
+
+ if (data->flags.bits.ENABLE_HW ||
+ data->flags.bits.REPROGRAM_HW) {
+ data->flags.all = 0;
+ data->flags.bits.EXISTING = true;
+ }
+
+ data->flags.bits.POST_ACTION_DISPLAY_ON = display_on;
+ }
+ }
+
+ dal_tm_force_update_scratch_active_and_requested(ds->tm);
+}
+
+
+/*
+ * hw_mode_info_from_path_mode
+ *
+ * Convert path mode into HW path mode
+ */
+static void hw_mode_info_from_path_mode(
+ const struct ds_dispatch *ds_dispatch,
+ struct hw_mode_info *info,
+ struct display_path *display_path,
+ const struct path_mode *mode,
+ enum build_path_set_reason reason)
+{
+ convert_mode_info(ds_dispatch, info, display_path, mode, reason);
+
+ /* TODO: Overlay implementation */
+
+ /* TODO: Display state container implementation */
+ /* TODO: Set color space */
+
+ /* TODO: Set scaling info. Function for this should be ported and
+ * following 4 assignment should be removed */
+
+ info->color_space = dal_grph_colors_group_get_color_space(
+ ds_dispatch->grph_colors_adj,
+ &mode->mode_timing->crtc_timing,
+ display_path,
+ dal_ds_dispatch_get_adj_container_for_path(
+ ds_dispatch,
+ mode->display_path_index));
+
+ info->scaling_info.dst.height =
+ mode->mode_timing->mode_info.pixel_height;
+ info->scaling_info.dst.width =
+ mode->mode_timing->mode_info.pixel_width;
+ info->scaling_info.src = info->view;
+
+ info->scaling_info.signal =
+ dal_display_path_get_config_signal(
+ display_path, SINK_LINK_INDEX);
+
+ set_dithering_options(ds_dispatch, info, mode, display_path);
+}
+
+/*
+ * update_ranged_timing_feature_preferences
+ *
+ * When there is a change in ranged timing feature preference, flags need to be
+ * updated. This may be a transition between VSYNC phase requirement where we
+ * are switching from programming ranged timing parameters from supporting
+ * DRR -> PSR. This may also be for test interface to force DRR disabled, in
+ * which case a flag should indicate ranged timing registers be programmed 0.
+ */
+static void update_ranged_timing_feature_preferences(
+ struct ds_dispatch *ds,
+ uint32_t display_path_index,
+ struct ranged_timing_preference_flags pref_flags)
+{
+ struct active_path_data *path_data =
+ dal_pms_with_data_get_path_data_for_display_index(
+ ds->set,
+ display_path_index);
+
+ if (path_data != NULL)
+ path_data->ranged_timing_pref_flags.u32all = pref_flags.u32all;
+}
+
+/*
+ *
+ * tune_up_timing
+ * Tune up timing
+ */
+static void tune_up_timing(
+ struct ds_dispatch *ds,
+ struct display_path *display_path,
+ struct hw_path_mode *hw_mode)
+{
+ struct timing_limits timing_limits;
+
+ if (dal_dcs_get_timing_limits(dal_display_path_get_dcs(display_path),
+ &timing_limits)) {
+ struct pixel_clock_safe_range pixel_clock_safe_range;
+ struct ranged_timing_preference_flags pref_flags;
+ struct active_path_data *path_data;
+ uint32_t display_index = dal_display_path_get_display_index(
+ display_path);
+
+ /* Get requested limits */
+ if (dal_display_path_get_pixel_clock_safe_range(
+ display_path,
+ &pixel_clock_safe_range)) {
+ if (timing_limits.min_pixel_clock_in_khz <
+ pixel_clock_safe_range.min_frequency) {
+ timing_limits.min_pixel_clock_in_khz =
+ pixel_clock_safe_range.min_frequency;
+ }
+ if (timing_limits.max_pixel_clock_in_khz >
+ pixel_clock_safe_range.max_frequency) {
+ timing_limits.max_pixel_clock_in_khz =
+ pixel_clock_safe_range.max_frequency;
+ }
+ } else {
+ /* Not a safe pixel clock, clear max pixel clock and
+ * min pixel clock. tune_up_timing function will not
+ * tune timing for safe pixel clock feature, but may
+ * still need to tune timing for DRR feature. */
+ timing_limits.min_pixel_clock_in_khz = 0;
+ timing_limits.max_pixel_clock_in_khz = 0;
+ }
+
+ /* During reset of path, reset ranged timing flags. */
+ pref_flags.u32all = 0;
+ if (hw_mode->action == HW_PATH_ACTION_RESET) {
+ update_ranged_timing_feature_preferences(
+ ds,
+ display_index,
+ pref_flags);
+ }
+
+ /* Use flags from active_path_data if exists, otherwise flags
+ * will not be set and default behaviour will be used while
+ * building ranged timing. */
+ path_data =
+ dal_pms_with_data_get_path_data_for_display_index(
+ ds->set,
+ display_index);
+ if (path_data != NULL) {
+ pref_flags.u32all =
+ path_data->ranged_timing_pref_flags.u32all;
+ }
+
+ dal_ds_calculation_setup_ranged_timing(
+ &hw_mode->mode.timing,
+ display_path,
+ pref_flags);
+ dal_ds_calculation_tuneup_timing(
+ &hw_mode->mode.timing,
+ &timing_limits);
+ }
+}
+
+/*
+ * build_adjustment_set
+ *
+ * Build a set of adjustments
+ */
+static bool build_adjustment_set(
+ struct ds_dispatch *ds,
+ struct hw_path_mode *hw_mode,
+ const struct path_mode *mode,
+ struct display_path *display_path,
+ enum build_path_set_reason reason)
+{
+ struct adj_container *container;
+ struct hw_adjustment_set *set = NULL;
+
+ hw_mode->adjustment_set = NULL;
+ dal_ds_dispatch_update_adj_container_for_path_with_mode_info(
+ ds,
+ display_path,
+ mode);
+ container = dal_ds_dispatch_get_adj_container_for_path(
+ ds,
+ mode->display_path_index);
+ dal_ds_dispatch_apply_scaling(
+ ds,
+ mode,
+ container,
+ reason,
+ hw_mode);
+
+ if (reason == BUILD_PATH_SET_REASON_SET_MODE) {
+ set = dal_alloc(sizeof(*set));
+ if (set == NULL)
+ return false;
+ dal_ds_dispatch_build_include_adj(
+ ds,
+ mode,
+ display_path,
+ hw_mode,
+ set);
+ if (hw_mode->action == HW_PATH_ACTION_SET)
+ dal_ds_dispatch_build_post_set_mode_adj(
+ ds,
+ mode,
+ display_path,
+ set);
+ dal_ds_dispatch_build_color_control_adj(
+ ds,
+ mode,
+ display_path,
+ set);
+ }
+ hw_mode->adjustment_set = set;
+
+ return true;
+}
+
+/*
+ * setup_additional_parameters
+ *
+ * Set up additional parameters for HW path mode
+ */
+static void setup_additional_parameters(
+ const struct path_mode *mode,
+ struct hw_path_mode *hw_mode)
+{
+ hw_mode->mode.ds_info.original_timing = hw_mode->mode.timing;
+ hw_mode->mode.ds_info.DISPLAY_PREFERED_MODE =
+ mode->mode_timing->mode_info.flags.PREFERRED;
+ hw_mode->mode.underscan_rule = HW_SCALE_OPTION_UNKNOWN;
+}
+
+/*
+ * set_dithering_options
+ *
+ * Set dithering
+ */
+static void set_dithering_options(
+ const struct ds_dispatch *ds_dispatch,
+ struct hw_mode_info *info,
+ const struct path_mode *mode,
+ struct display_path *display_path)
+{
+ enum signal_type signal;
+
+ /* Check for dithering restrictions
+ * 1. only digital, except LVDS/eDP which is handled by VBIOS
+ * 2. since surface output stream is always in 10bpc,
+ * dithering is only required for 6 and 8 bpc
+ * 3. dithering can be applied only for RGB and YCbCr444
+ * 4. packed pixel formats can't use dithering */
+
+ if ((mode->mode_timing->crtc_timing.pixel_encoding !=
+ PIXEL_ENCODING_YCBCR422) &&
+ (mode->mode_timing->crtc_timing.display_color_depth <
+ DISPLAY_COLOR_DEPTH_101010) &&
+ (dal_dcs_get_enabled_packed_pixel_format(
+ dal_display_path_get_dcs(display_path)) ==
+ DCS_PACKED_PIXEL_FORMAT_NOT_PACKED))
+ info->dithering = HW_DITHERING_OPTION_ENABLE;
+ else
+ info->dithering = HW_DITHERING_OPTION_SKIP_PROGRAMMING;
+
+
+ signal = dal_display_path_get_config_signal(
+ display_path, ASIC_LINK_INDEX);
+
+ switch (signal) {
+ case SIGNAL_TYPE_DVI_SINGLE_LINK:
+ case SIGNAL_TYPE_DVI_DUAL_LINK:
+ if (dal_adapter_service_is_feature_supported(
+ FEATURE_TMDS_DISABLE_DITHERING))
+ info->dithering = HW_DITHERING_OPTION_DISABLE;
+ break;
+ case SIGNAL_TYPE_DISPLAY_PORT:
+ case SIGNAL_TYPE_DISPLAY_PORT_MST:
+ if (dal_adapter_service_is_feature_supported(
+ FEATURE_DP_DISABLE_DITHERING))
+ info->dithering = HW_DITHERING_OPTION_DISABLE;
+ break;
+ case SIGNAL_TYPE_DVO:
+ case SIGNAL_TYPE_DVO24:
+ /* do nothing since dithering option is already set to enable */
+ break;
+ case SIGNAL_TYPE_HDMI_TYPE_A:
+ if ((get_active_timing_3d_format(
+ mode->mode_timing->crtc_timing.timing_3d_format,
+ mode->view_3d_format) ==
+ TIMING_3D_FORMAT_SW_FRAME_PACKING) ||
+ dal_adapter_service_is_feature_supported(
+ FEATURE_HDMI_DISABLE_DITHERING))
+ info->dithering = HW_DITHERING_OPTION_DISABLE;
+ break;
+ case SIGNAL_TYPE_WIRELESS:
+ /* Enabling dithering will affect VCE bitrate management
+ * due to randomness of pixel data, so we should disable it */
+ info->dithering = HW_DITHERING_OPTION_DISABLE;
+ break;
+ case SIGNAL_TYPE_LVDS:
+ case SIGNAL_TYPE_EDP:
+ if (dal_adapter_service_is_feature_supported(
+ FEATURE_EMBEDDED_DISABLE_DITHERING))
+ info->dithering = HW_DITHERING_OPTION_SKIP_PROGRAMMING;
+ break;
+ default:
+ /* Dithering should be applied (usually due to incompatible
+ * or unsupported signal).
+ * Analog signal does not support dithering, and,
+ * since LVDS/eDP are handled by VBIOS,
+ * driver should not touch Formatter at all.
+ * Therefore, skip programming. */
+ info->dithering = HW_DITHERING_OPTION_SKIP_PROGRAMMING;
+ break;
+ }
+}
+
+static void patch_hw_view_for_3d(
+ struct view *view,
+ const struct crtc_timing *crtc_timing,
+ enum view_3d_format view_3d_format)
+{
+ if (get_active_timing_3d_format(
+ crtc_timing->timing_3d_format, view_3d_format) ==
+ TIMING_3D_FORMAT_SW_FRAME_PACKING) {
+ ASSERT(view->height == crtc_timing->v_addressable);
+ view->height =
+ crtc_timing->v_total + crtc_timing->v_addressable;
+ }
+}
+
+/*
+ * convert_mode_info
+ *
+ * Helper to convert path mode into hw path mode
+ */
+static void convert_mode_info(
+ const struct ds_dispatch *ds,
+ struct hw_mode_info *info,
+ struct display_path *display_path,
+ const struct path_mode *mode,
+ enum build_path_set_reason reason)
+{
+ enum signal_type asic_signal;
+ enum scaling_transformation scl_type;
+
+ info->view.height = mode->view.height;
+ info->view.width = mode->view.width;
+
+ patch_hw_view_for_3d(
+ &info->view,
+ &mode->mode_timing->crtc_timing,
+ mode->view_3d_format);
+
+ info->refresh_rate = mode->mode_timing->mode_info.field_rate;
+
+ info->pixel_format = mode->pixel_format;
+
+ info->tiling_mode = mode->tiling_mode;
+
+ info->is_tiling_rotated = mode->is_tiling_rotated;
+ info->rotation = mode->rotation_angle;
+
+ /* temporary */
+ info->ds_info.cea_vic = mode->mode_timing->crtc_timing.vic;
+
+ /* should be updated by wrapping function */
+ info->color_space = HW_COLOR_SPACE_UNKNOWN;
+
+ asic_signal = dal_display_path_get_config_signal(
+ display_path, ASIC_LINK_INDEX);
+
+ hw_crtc_timing_from_crtc_timing(
+ &info->timing,
+ &mode->mode_timing->crtc_timing,
+ mode->view_3d_format,
+ asic_signal);
+
+ setup_hw_stereo_mixer_params(
+ info,
+ &mode->mode_timing->crtc_timing,
+ mode->view_3d_format);
+
+ scl_type = mode->scaling;
+
+ /* TODO: add DTO timing processing and scl_type change */
+
+ /*build scaler overscan parameters for new_mode*/
+ build_scaling_params(ds, mode, scl_type, info);
+}
+
+static enum timing_3d_format get_active_timing_3d_format(
+ enum timing_3d_format timing_3d_format,
+ enum view_3d_format view_3d_format)
+{
+ return (view_3d_format != timing_3d_format_to_view_3d_format(
+ timing_3d_format)) ? TIMING_3D_FORMAT_NONE : timing_3d_format;
+}
+
+/*
+ * hw_crtc_timing_from_crtc_timing
+ *
+ * Convert CRTC timing into HW format
+ */
+static void hw_crtc_timing_from_crtc_timing(
+ struct hw_crtc_timing *hw_timing,
+ const struct crtc_timing *timing,
+ enum view_3d_format view_3d_format,
+ enum signal_type signal)
+{
+ uint32_t pixel_repetition = timing->flags.PIXEL_REPETITION == 0 ?
+ 1 : timing->flags.PIXEL_REPETITION;
+
+ uint32_t vsync_offset = timing->v_border_bottom +
+ timing->v_front_porch - timing->flags.INTERLACE;
+
+ uint32_t hsync_offset = timing->h_border_right +
+ timing->h_front_porch;
+
+ enum timing_3d_format timing_3d_format;
+
+ hw_timing->h_total = timing->h_total / pixel_repetition;
+ hw_timing->h_addressable = timing->h_addressable / pixel_repetition;
+ hw_timing->h_overscan_left = timing->h_border_left / pixel_repetition;
+ hw_timing->h_overscan_right = timing->h_border_right / pixel_repetition;
+ hw_timing->h_sync_start = (timing->h_addressable + hsync_offset) /
+ pixel_repetition;
+ hw_timing->h_sync_width = timing->h_sync_width / pixel_repetition;
+
+ hw_timing->v_total = timing->v_total;
+ hw_timing->v_addressable = timing->v_addressable;
+ hw_timing->v_overscan_top = timing->v_border_top;
+ hw_timing->v_overscan_bottom = timing->v_border_bottom;
+ hw_timing->v_sync_start = timing->v_addressable + vsync_offset;
+ hw_timing->v_sync_width = timing->v_sync_width;
+
+ hw_timing->pixel_clock = timing->pix_clk_khz;
+
+ hw_timing->flags.INTERLACED = timing->flags.INTERLACE;
+ hw_timing->flags.DOUBLESCAN = timing->flags.DOUBLESCAN;
+ hw_timing->flags.PIXEL_REPETITION = pixel_repetition;
+ hw_timing->flags.HSYNC_POSITIVE_POLARITY =
+ timing->flags.HSYNC_POSITIVE_POLARITY;
+ hw_timing->flags.VSYNC_POSITIVE_POLARITY =
+ timing->flags.VSYNC_POSITIVE_POLARITY;
+ hw_timing->flags.RIGHT_EYE_3D_POLARITY =
+ timing->flags.RIGHT_EYE_3D_POLARITY;
+ hw_timing->flags.PACK_3D_FRAME = false;
+ hw_timing->flags.HIGH_COLOR_DL_MODE = false;
+ hw_timing->flags.Y_ONLY = timing->flags.YONLY;
+
+ /* Note: converting between two different enums directly */
+ hw_timing->flags.COLOR_DEPTH = timing->display_color_depth;
+ hw_timing->flags.PIXEL_ENCODING = timing->pixel_encoding;
+ hw_timing->timing_standard = timing->timing_standard;
+
+ if (signal == SIGNAL_TYPE_DVI_DUAL_LINK &&
+ timing->display_color_depth >= DISPLAY_COLOR_DEPTH_101010) {
+ if (hw_timing->pixel_clock > DVI_10BIT_THRESHOLD_RATE_IN_KHZ)
+ hw_timing->pixel_clock *= 2;
+
+ hw_timing->flags.HIGH_COLOR_DL_MODE = true;
+ }
+
+ /* Adjust HW timing for 3D Frame Packing format,
+ * according to HDMI specs:
+ * 1. 3D pixel clock frequency is x2 of 2D pixel clock frequency
+ * 2. 3D vertical total lines is x2 of 2D vertical total lines
+ * 3. 3D horizontal total pixels is equal to 2D horizontal total pixels
+ */
+
+ timing_3d_format = get_active_timing_3d_format(
+ timing->timing_3d_format, view_3d_format);
+
+ switch (timing_3d_format) {
+ case TIMING_3D_FORMAT_HW_FRAME_PACKING:
+ /* HW will adjust image size.
+ * Here we need only adjust pixel clock */
+ hw_timing->pixel_clock *= 2;
+ hw_timing->flags.PACK_3D_FRAME = true;
+ break;
+ case TIMING_3D_FORMAT_SW_FRAME_PACKING: {
+ /* HW does not support frame packing.
+ * Need to adjust image and pixel clock */
+ uint32_t blank_region =
+ hw_timing->v_total - hw_timing->v_addressable;
+
+ hw_timing->v_total *= 2;
+ hw_timing->v_addressable = hw_timing->v_total - blank_region;
+ hw_timing->v_sync_start =
+ hw_timing->v_addressable + vsync_offset;
+ hw_timing->pixel_clock *= 2;
+ break;
+ }
+ case TIMING_3D_FORMAT_DP_HDMI_INBAND_FA:
+ /* When we try to set frame packing with a HDMI display
+ * which is connected via active DP-HDMI dongle,
+ * we want to use HDMI frame packing,
+ * so the pixel clock is doubled. */
+ hw_timing->pixel_clock *= 2;
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * Initialize ranged_timing for DRR/Freesync
+ */
+ hw_timing->ranged_timing.vertical_total_min = 0;
+ hw_timing->ranged_timing.vertical_total_max = 0;
+ hw_timing->ranged_timing.control.force_lock_on_event = 0;
+ hw_timing->ranged_timing.control.lock_to_master_vsync = 0;
+}
+
+/*
+ * setup_hw_stereo_mixer_params
+ *
+ * Setup HW stereo mixer parameters
+ */
+static void setup_hw_stereo_mixer_params(
+ struct hw_mode_info *info,
+ const struct crtc_timing *crtc_timing,
+ enum view_3d_format view_3d_format)
+{
+ enum timing_3d_format timing_3d_format =
+ get_active_timing_3d_format(
+ crtc_timing->timing_3d_format, view_3d_format);
+
+ switch (timing_3d_format) {
+ case TIMING_3D_FORMAT_ROW_INTERLEAVE:
+ info->stereo_format = HW_STEREO_FORMAT_ROW_INTERLEAVED;
+ info->stereo_mixer_params.sub_sampling =
+ crtc_timing->flags.SUB_SAMPLE_3D;
+ break;
+ case TIMING_3D_FORMAT_COLUMN_INTERLEAVE:
+ info->stereo_format = HW_STEREO_FORMAT_COLUMN_INTERLEAVED;
+ info->stereo_mixer_params.sub_sampling =
+ crtc_timing->flags.SUB_SAMPLE_3D;
+ break;
+ case TIMING_3D_FORMAT_PIXEL_INTERLEAVE:
+ info->stereo_format = HW_STEREO_FORMAT_CHECKER_BOARD;
+ info->stereo_mixer_params.sub_sampling =
+ crtc_timing->flags.SUB_SAMPLE_3D;
+ break;
+ default:
+ info->stereo_format = HW_STEREO_FORMAT_NONE;
+ break;
+ }
+
+ /* If we have SBS_AppPacked OR TB_AppPacked timing on Frame Sequential
+ * view format, then we know that single pipe is enabled and hence we
+ * store the format/mode based on the timing. */
+ if (view_3d_format == VIEW_3D_FORMAT_FRAME_SEQUENTIAL) {
+ switch (timing_3d_format) {
+ case TIMING_3D_FORMAT_SIDE_BY_SIDE:
+ info->stereo_format = HW_STEREO_FORMAT_SIDE_BY_SIDE;
+ info->stereo_mixer_params.single_pipe = true;
+ break;
+ case TIMING_3D_FORMAT_TOP_AND_BOTTOM:
+ info->stereo_format = HW_STEREO_FORMAT_TOP_AND_BOTTOM;
+ info->stereo_mixer_params.single_pipe = true;
+ break;
+ default:
+ break;
+ }
+ } /* if() */
+}
+
+static enum view_3d_format timing_3d_format_to_view_3d_format(
+ enum timing_3d_format timing_3d_format)
+{
+ switch (timing_3d_format) {
+ case TIMING_3D_FORMAT_SIDEBAND_FA:
+ case TIMING_3D_FORMAT_INBAND_FA:
+ case TIMING_3D_FORMAT_DP_HDMI_INBAND_FA:
+ case TIMING_3D_FORMAT_FRAME_ALTERNATE:
+ case TIMING_3D_FORMAT_HW_FRAME_PACKING:
+ case TIMING_3D_FORMAT_SW_FRAME_PACKING:
+ case TIMING_3D_FORMAT_ROW_INTERLEAVE:
+ case TIMING_3D_FORMAT_COLUMN_INTERLEAVE:
+ case TIMING_3D_FORMAT_PIXEL_INTERLEAVE:
+ return VIEW_3D_FORMAT_FRAME_SEQUENTIAL;
+ case TIMING_3D_FORMAT_SBS_SW_PACKED:
+ return VIEW_3D_FORMAT_SIDE_BY_SIDE;
+ case TIMING_3D_FORMAT_TB_SW_PACKED:
+ return VIEW_3D_FORMAT_TOP_AND_BOTTOM;
+ default:
+ return VIEW_3D_FORMAT_NONE;
+ }
+}
+
+static bool validate_stereo_3d_format(
+ struct display_path *display_path,
+ const struct crtc_timing *crtc_timing,
+ enum view_3d_format view_3d_format)
+{
+ enum timing_3d_format timing_3d_format = get_active_timing_3d_format(
+ crtc_timing->timing_3d_format, view_3d_format);
+
+ enum signal_type signal = dal_display_path_get_query_signal(
+ display_path, SINK_LINK_INDEX);
+
+ switch (timing_3d_format) {
+ case TIMING_3D_FORMAT_HW_FRAME_PACKING:
+ case TIMING_3D_FORMAT_SW_FRAME_PACKING:
+ /* Frame packing is defined only by DP and HDMI specs */
+ return dal_is_hdmi_signal(signal) || dal_is_dp_signal(signal);
+ case TIMING_3D_FORMAT_SBS_SW_PACKED:
+ case TIMING_3D_FORMAT_TB_SW_PACKED:
+ /* Driver supports only HDMI signaling for these formats */
+ return dal_is_hdmi_signal(signal);
+ default:
+ return true;
+ }
+}
+
+static void enable_gtc_embedding(
+ struct ds_dispatch *ds_dispatch,
+ struct hw_path_mode_set *hw_mode_set)
+{
+ /* TODO implement */
+}
+
+
+/*
+ * is_gamut_change_required
+ *
+ * @brief
+ * Check if gamut needs reprogramming
+ *
+ * @param
+ * enum pixel_encoding pixel_encoding: [in] pixel encoding
+ * enum pixel_format pixel_format: [in] pixel format
+ * uint32_t disp_index: [in] display index
+ *
+ * @return
+ * True if gamut needs to be reprogrammed, false otherwise
+ */
+bool dal_ds_dispatch_is_gamut_change_required(
+ struct ds_dispatch *ds_dispatch,
+ enum pixel_encoding pixel_encoding,
+ enum pixel_format pixel_format,
+ uint32_t disp_index)
+{
+ /* TODO: Implement adjustment */
+ return false;
+}
+
+static void destruct_adjustment_set(struct hw_adjustment_set *set)
+{
+ if (set->backlight != NULL)
+ dal_free(set->backlight);
+ if (set->bit_depth != NULL)
+ dal_free(set->bit_depth);
+ if (set->coherent != NULL)
+ dal_free(set->coherent);
+ if (set->color_control != NULL)
+ dal_free(set->color_control);
+ if (set->composite_sync != NULL)
+ dal_free(set->composite_sync);
+ if (set->deflicker_filter != NULL)
+ dal_free(set->deflicker_filter);
+ if (set->gamma_ramp != NULL)
+ dal_free(set->gamma_ramp);
+ if (set->h_sync != NULL)
+ dal_free(set->h_sync);
+ if (set->v_sync != NULL)
+ dal_free(set->v_sync);
+ if (set->vb_level != NULL)
+ dal_free(set->vb_level);
+}
+
+static void destroy_adjustment_set(
+ struct hw_adjustment_set **set)
+{
+ if (set == NULL || *set == NULL)
+ return;
+ destruct_adjustment_set(*set);
+ dal_free(*set);
+ *set = NULL;
+}
+
+static void send_wireless_setmode_end_event(
+ struct ds_dispatch *ds,
+ const struct path_mode_set *path_mode_set)
+{
+ uint32_t i;
+ uint32_t path_mode_num = dal_pms_get_path_mode_num(path_mode_set);
+
+ for (i = 0; i < path_mode_num; i++) {
+ const struct path_mode *path_mode_in =
+ dal_pms_get_path_mode_at_index(
+ path_mode_set, i);
+ uint32_t disp_index = path_mode_in->display_path_index;
+
+ struct display_path *disp_path = NULL;
+ enum signal_type signal;
+
+ disp_path = dal_tm_display_index_to_display_path(
+ ds->tm,
+ disp_index);
+
+ signal = dal_display_path_get_active_signal(
+ disp_path, SINK_LINK_INDEX);
+
+ if (SIGNAL_TYPE_WIRELESS == signal) {
+
+ const struct mode_timing *mode_timing =
+ path_mode_in->mode_timing;
+
+ const struct crtc_timing *crtc_timing =
+ &mode_timing->crtc_timing;
+
+ uint32_t h_active = crtc_timing->h_addressable +
+ crtc_timing->h_border_left +
+ crtc_timing->h_border_right;
+
+ uint32_t v_active = crtc_timing->v_addressable +
+ crtc_timing->v_border_top +
+ crtc_timing->v_border_bottom;
+
+
+ dal_notify_setmode_complete(
+ ds->dal_context,
+ crtc_timing->h_total,
+ crtc_timing->v_total,
+ h_active,
+ v_active,
+ crtc_timing->pix_clk_khz);
+ }
+ }
+}
diff --git a/drivers/gpu/drm/amd/dal/display_service/ds_dispatch_planes.c b/drivers/gpu/drm/amd/dal/display_service/ds_dispatch_planes.c
new file mode 100644
index 000000000000..920a2b287cf0
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/ds_dispatch_planes.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2015 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 */
+#include "dal_services.h"
+
+#include "include/set_mode_interface.h"
+#include "include/hw_sequencer_interface.h"
+#include "include/hw_path_mode_set_interface.h"
+#include "include/topology_mgr_interface.h"
+
+#include "ds_dispatch.h"
+
+
+enum ds_return dal_ds_dispatch_setup_plane_configurations(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ uint32_t planes_num,
+ const struct plane_config *configs)
+{
+ enum ds_return result = DS_SUCCESS;
+ uint32_t path_num = dal_pms_with_data_get_path_mode_num(ds->set);
+ struct hw_path_mode_set *hw_mode_set = dal_hw_path_mode_set_create();
+
+ if (!hw_mode_set) {
+ BREAK_TO_DEBUGGER();
+ return DS_ERROR;
+ }
+
+ /* Convert path mode set into HW path mode set for HWSS
+ * This is needed for dal_hw_sequencer_prepare_to_release_planes
+ * to get hw_mode_set*/
+ if (false == dal_ds_dispatch_build_hw_path_set(
+ ds,
+ path_num,
+ dal_pms_with_data_get_path_mode_at_index(
+ ds->set,
+ 0),
+ hw_mode_set,
+ BUILD_PATH_SET_REASON_SET_MODE,
+ NULL)) {
+ /* error */
+ result = DS_ERROR;
+ }
+
+ /* HW programming */
+ if (DS_SUCCESS == result) {
+ /* clean-up part */
+ dal_hw_sequencer_prepare_to_release_planes(
+ ds->hwss,
+ hw_mode_set,
+ display_index);
+ dal_tm_release_plane_resources(
+ ds->tm,
+ display_index);
+ dal_pms_with_data_clear_plane_configs(ds->set, display_index);
+
+ dal_tm_acquire_plane_resources(
+ ds->tm,
+ display_index,
+ planes_num,
+ configs);
+
+ dal_pms_with_data_add_plane_configs(
+ ds->set,
+ display_index,
+ configs,
+ planes_num);
+
+ /*Because configs may be update, hw_mode_set needs
+ *to be re-built*/
+ if (false == dal_ds_dispatch_build_hw_path_set(
+ ds,
+ path_num,
+ dal_pms_with_data_get_path_mode_at_index(
+ ds->set,
+ 0),
+ hw_mode_set,
+ BUILD_PATH_SET_REASON_GET_ACTIVE_PATHS,
+ NULL)) {
+ /* error */
+ result = DS_ERROR;
+ }
+
+ if (DS_SUCCESS == result)
+ if (dal_hw_sequencer_set_plane_config(
+ ds->hwss,
+ hw_mode_set,
+ display_index) != HWSS_RESULT_OK)
+ result = DS_ERROR;
+ }
+
+ dal_ds_dispatch_destroy_hw_path_set(hw_mode_set);
+
+ return result;
+}
+
+bool dal_ds_dispatch_validate_plane_configurations(
+ struct ds_dispatch *ds,
+ uint32_t num_planes,
+ const struct plane_config *pl_configs,
+ bool *supported)
+{
+ uint32_t i;
+
+ /* For now, we just return true for all planes */
+ for (i = 0; i < num_planes; i++)
+ supported[i] = true;
+
+ return true;
+}
diff --git a/drivers/gpu/drm/amd/dal/display_service/ds_overlay.c b/drivers/gpu/drm/amd/dal/display_service/ds_overlay.c
new file mode 100644
index 000000000000..6b5aa11d88b0
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/ds_overlay.c
@@ -0,0 +1,202 @@
+/*
+ * 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/overlay_interface.h"
+
+
+bool dal_ds_overlay_is_active(
+ struct ds_overlay *ovl,
+ uint32_t display_index)
+{
+ /*TODO: add implementation*/
+ return false;
+}
+
+uint32_t dal_ds_overlay_get_controller_handle(
+ struct ds_overlay *ovl,
+ uint32_t display_index)
+{
+ /*TODO: add implementation*/
+ return 0;
+}
+
+enum ds_return dal_ds_overlay_alloc(
+ struct ds_overlay *ovl,
+ struct path_mode_set *path_mode_set,
+ uint32_t display_index,
+ struct view *view,
+ struct overlay_data *data)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_ds_overlay_validate(
+ struct ds_overlay *ovl,
+ struct path_mode_set *path_mode_set,
+ uint32_t display_index,
+ struct view *view,
+ struct overlay_data *data)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_ds_overlay_free(
+ struct ds_overlay *ovl,
+ struct path_mode_set *path_mode_set,
+ uint32_t display_index)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_ds_overlay_get_info(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ enum overlay_color_space *color_space,
+ enum overlay_backend_bpp *backend_bpp,
+ enum overlay_alloc_option *alloc_option,
+ enum overlay_format *surface_format)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_ds_overlay_set_otm(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ const struct path_mode *current_path_mode)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+enum ds_return dal_ds_overlay_reset_otm(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ struct path_mode **saved_path_mode)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+/**is in overlay theater mode*/
+bool dal_ds_overlay_is_in_otm(
+ struct ds_overlay *ovl,
+ uint32_t display_index)
+{
+ /*TODO: add implementation*/
+ return false;
+}
+
+void dal_ds_overlay_set_matrix(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ const struct overlay_color_matrix *matrix)
+{
+ /*TODO: add implementation*/
+}
+
+void dal_ds_overlay_reset_matrix(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ enum overlay_csc_matrix_type type)
+{
+ /*TODO: add implementation*/
+}
+
+const struct overlay_color_matrix *dal_ds_overlay_get_matrix(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ enum overlay_csc_matrix_type type)
+{
+ /*TODO: add implementation*/
+ return NULL;
+}
+
+bool dal_ds_overlay_set_color_space(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ enum overlay_color_space space)
+{
+ /*TODO: add implementation*/
+ return false;
+}
+
+bool dal_ds_overlay_get_display_pixel_encoding(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ enum display_pixel_encoding *pixel_encoding)
+{
+ /*TODO: add implementation*/
+ return false;
+}
+
+bool dal_ds_overlay_set_display_pixel_encoding(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ enum display_pixel_encoding pixel_encoding)
+{
+ /*TODO: add implementation*/
+ return false;
+}
+
+bool dal_ds_overlay_reset_display_pixel_encoding(
+ struct ds_overlay *ovl,
+ uint32_t display_index)
+{
+ /*TODO: add implementation*/
+ return false;
+}
+
+/*After Set Overlay Theatre Mode (OTM) on a display path,
+ * saving the passed setting of Gpu scaling option for later restore*/
+enum ds_return dal_ds_overlay_save_gpu_scaling_before_otm(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ int32_t timing_sel_before_otm)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+/* After reset Overlay Theatre Mode (OTM) on a display path,
+ * returning the previous Gpu scaling option by SetOverlayTheatreMode*/
+enum ds_return dal_ds_overlay_get_gpu_scaling_before_otm(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ int32_t *timing_sel_before_otm)
+{
+ /*TODO: add implementation*/
+ return DS_ERROR;
+}
+
+uint32_t dal_ds_overlay_get_num_of_allowed(struct ds_overlay *ovl)
+{
+ /*TODO: add implementation*/
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/dal/display_service/ds_translation.c b/drivers/gpu/drm/amd/dal/display_service/ds_translation.c
new file mode 100644
index 000000000000..5bc50040d6b5
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/ds_translation.c
@@ -0,0 +1,560 @@
+/*
+ * 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/hw_sequencer_types.h"
+
+#include "ds_translation.h"
+#include "adjustment_types_internal.h"
+
+/*
+ * ds_translation_translate_content_type
+ *
+ * Translate adjustment value into supported display content type
+ *
+ * uint32_t val - adjustment value
+ * union display_content_type *support - supported display content type
+ *
+ * return void
+ */
+void dal_ds_translation_translate_content_type(uint32_t val,
+ enum display_content_type *support)
+{
+ switch (val) {
+ case DISPLAY_CONTENT_TYPE_GRAPHICS:
+ *support = DISPLAY_CONTENT_TYPE_GRAPHICS;
+ break;
+
+ case DISPLAY_CONTENT_TYPE_PHOTO:
+ *support = DISPLAY_CONTENT_TYPE_PHOTO;
+ break;
+
+ case DISPLAY_CONTENT_TYPE_CINEMA:
+ *support = DISPLAY_CONTENT_TYPE_CINEMA;
+ break;
+
+ case DISPLAY_CONTENT_TYPE_GAME:
+ *support = DISPLAY_CONTENT_TYPE_GAME;
+ break;
+
+ default:
+ *support = DISPLAY_CONTENT_TYPE_NO_DATA;
+ }
+}
+
+/* Translate 3D format */
+enum timing_3d_format dal_ds_translation_get_active_timing_3d_format(
+ enum timing_3d_format timing_format,
+ enum view_3d_format view_format)
+{
+ enum view_3d_format target_format =
+ dal_ds_translation_3d_format_timing_to_view(
+ timing_format);
+
+ if (target_format != view_format)
+ return TIMING_3D_FORMAT_NONE;
+
+ return timing_format;
+}
+
+/* Translate timing 3D format to view 3D format*/
+enum view_3d_format dal_ds_translation_3d_format_timing_to_view(
+ enum timing_3d_format timing_format)
+{
+ enum view_3d_format view_format = VIEW_3D_FORMAT_NONE;
+
+ switch (timing_format) {
+ case TIMING_3D_FORMAT_SIDEBAND_FA:
+ case TIMING_3D_FORMAT_INBAND_FA:
+ case TIMING_3D_FORMAT_FRAME_ALTERNATE:
+ case TIMING_3D_FORMAT_HW_FRAME_PACKING:
+ case TIMING_3D_FORMAT_SW_FRAME_PACKING:
+ case TIMING_3D_FORMAT_ROW_INTERLEAVE:
+ case TIMING_3D_FORMAT_COLUMN_INTERLEAVE:
+ case TIMING_3D_FORMAT_PIXEL_INTERLEAVE:
+ view_format = VIEW_3D_FORMAT_FRAME_SEQUENTIAL;
+ break;
+
+ case TIMING_3D_FORMAT_SBS_SW_PACKED:
+ view_format = VIEW_3D_FORMAT_SIDE_BY_SIDE;
+ break;
+
+ case TIMING_3D_FORMAT_TB_SW_PACKED:
+ view_format = VIEW_3D_FORMAT_TOP_AND_BOTTOM;
+ break;
+
+ default:
+ break;
+ }
+
+ return view_format;
+}
+
+/*
+ * dal_ds_translation_patch_hw_view_for_3d
+ *
+ * Adjust HW view for 3D Frame Packing format (according to HDMI spec).
+ * This is relevant only 3D timing packed by SW.
+ * Also assumes if 3D timing packed by SW, then no scaling available.
+ * 1. NewVTotal = OldVTotal * 2
+ * 2. NewVBlank = OldVBlank (reminder: VBlank includes borders)
+ * 3. NewView = NewVTotal - NewVBlank
+ *
+ */
+void dal_ds_translation_patch_hw_view_for_3d(
+ struct view *view,
+ const struct crtc_timing *timing,
+ enum view_3d_format view_3d_format)
+{
+
+ /* Adjust HW view for 3D Frame Packing format (according to HDMI spec)
+ * 1. NewVTotal = OldVTotal * 2
+ * 2. NewVBlank = OldVBlank (reminder: VBlank includes borders)
+ * 3. NewView = NewVTotal - NewVBlank
+ */
+ if (dal_ds_translation_get_active_timing_3d_format(
+ timing->timing_3d_format,
+ view_3d_format) == TIMING_3D_FORMAT_SW_FRAME_PACKING) {
+ uint32_t blank_region = timing->v_total -
+ timing->v_addressable;
+ ASSERT(view->height == timing->v_addressable);
+ view->height = (timing->v_total * 2) - blank_region;
+ }
+}
+
+#define DVI_10_BIT_TRESHOLD_RATE_IN_KHZ 50000
+
+/*
+ * dal_ds_translation_hw_crtc_timing_from_crtc_timing
+ *
+ * Converts SW layer timing structure into HW layer timing structure.
+ * additional input parameters maybe present for proper conversion.
+ *
+ */
+void dal_ds_translation_hw_crtc_timing_from_crtc_timing(
+ struct hw_crtc_timing *hw_timing,
+ const struct crtc_timing *timing,
+ enum view_3d_format view_3d_format,
+ enum signal_type signal)
+{
+ enum timing_3d_format timing_3d_format;
+ uint32_t pixel_repetition =
+ timing->flags.PIXEL_REPETITION == 0 ?
+ 1 : timing->flags.PIXEL_REPETITION;
+
+ /* HW expects FrontPorch - 1 for interlaced modes */
+ uint32_t vsync_offset = timing->v_border_bottom +
+ (timing->v_front_porch - timing->flags.INTERLACE);
+ uint32_t hsync_offset = timing->h_border_right +
+ timing->h_front_porch;
+
+ hw_timing->h_total = timing->h_total / pixel_repetition;
+ hw_timing->h_addressable = timing->h_addressable / pixel_repetition;
+ hw_timing->h_overscan_left = timing->h_border_left / pixel_repetition;
+ hw_timing->h_overscan_right = timing->h_border_right / pixel_repetition;
+ hw_timing->h_sync_start = (timing->h_addressable + hsync_offset) /
+ pixel_repetition;
+ hw_timing->h_sync_width = timing->h_sync_width / pixel_repetition;
+
+ hw_timing->v_total = timing->v_total;
+ hw_timing->v_addressable = timing->v_addressable;
+ hw_timing->v_overscan_top = timing->v_border_top;
+ hw_timing->v_overscan_bottom = timing->v_border_bottom;
+ hw_timing->v_sync_width = timing->v_sync_width;
+ hw_timing->v_sync_start = timing->v_addressable + vsync_offset;
+
+ hw_timing->pixel_clock = timing->pix_clk_khz;
+
+ /* flags */
+ hw_timing->flags.INTERLACED = timing->flags.INTERLACE;
+ hw_timing->flags.DOUBLESCAN = timing->flags.DOUBLESCAN;
+ hw_timing->flags.PIXEL_REPETITION = pixel_repetition;
+ hw_timing->flags.HSYNC_POSITIVE_POLARITY =
+ timing->flags.HSYNC_POSITIVE_POLARITY;
+ hw_timing->flags.VSYNC_POSITIVE_POLARITY =
+ timing->flags.VSYNC_POSITIVE_POLARITY;
+ hw_timing->flags.RIGHT_EYE_3D_POLARITY =
+ timing->flags.RIGHT_EYE_3D_POLARITY;
+ hw_timing->flags.PACK_3D_FRAME = false;
+ hw_timing->flags.HIGH_COLOR_DL_MODE = false;
+ hw_timing->flags.Y_ONLY = timing->flags.YONLY;
+
+ /* below work only because HW def is clone of TS def.
+ * need translation to make this robust */
+ hw_timing->flags.COLOR_DEPTH =
+ (enum hw_color_depth) timing->display_color_depth;
+ hw_timing->flags.PIXEL_ENCODING =
+ (enum hw_pixel_encoding) timing->pixel_encoding;
+ hw_timing->timing_standard =
+ (enum hw_timing_standard) timing->timing_standard;
+
+ /* Adjust HW timing for DVI DualLink 10bit. For low clocks we do not
+ * double pixel rate */
+ if (signal == SIGNAL_TYPE_DVI_DUAL_LINK &&
+ timing->display_color_depth >= DISPLAY_COLOR_DEPTH_101010) {
+ if (hw_timing->pixel_clock > DVI_10_BIT_TRESHOLD_RATE_IN_KHZ)
+ hw_timing->pixel_clock *= 2;
+
+ hw_timing->flags.HIGH_COLOR_DL_MODE = true;
+ }
+
+ /* Adjust HW timing for 3D Frame Packing format (according to HDMI spec)
+ * 1. 3D pixel clock frequency is x2 of 2D pixel clock frequency
+ * 2. 3D vertical total line is x2 of 2D vertical total line
+ * 3. 3D horizontal total pixel is equal to 2D horizontal total pixel
+ */
+ timing_3d_format = dal_ds_translation_get_active_timing_3d_format(
+ timing->timing_3d_format,
+ view_3d_format);
+ switch (timing_3d_format) {
+ /* HW will adjust image size. Here we need only adjust pixel clock.
+ * Otherwise we need to do it as following: */
+ case TIMING_3D_FORMAT_HW_FRAME_PACKING:
+ hw_timing->pixel_clock *= 2;
+ hw_timing->flags.PACK_3D_FRAME = true;
+ break;
+
+ /* HW does not support frame packing. Need to adjust image and
+ * pixel clock
+ * 1. NewVTotal = OldVTotal * 2
+ * 2. NewVBlank = OldVBlank (reminder: VBlank includes borders)
+ * 2. NewVSyncOffset = OldVSyncOffset
+ * 4. NewVAddressable = NewVTotal - NewVBlank
+ * 5. NewVSyncStart = NewVAddressable - NewVSyncOffset
+ */
+ case TIMING_3D_FORMAT_SW_FRAME_PACKING: {
+ uint32_t blank_region = hw_timing->v_total -
+ hw_timing->v_addressable;
+ hw_timing->v_total *= 2;
+ hw_timing->v_addressable = hw_timing->v_total -
+ blank_region;
+ hw_timing->v_sync_start = hw_timing->v_addressable +
+ vsync_offset;
+ hw_timing->pixel_clock *= 2;
+
+ break;
+ }
+ case TIMING_3D_FORMAT_DP_HDMI_INBAND_FA:
+ /* When we try to set frame packing with a HDMI display that is
+ * connected via active DP-HDMI dongle, we want to use HDMI
+ * frame packing, so the pixel clock is doubled */
+ hw_timing->pixel_clock *= 2;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*
+* dal_ds_translation_setup_hw_stereo_mixer_params
+*
+* Setups Stereo Mixer parameters for HW sequencer
+*
+*/
+void dal_ds_translation_setup_hw_stereo_mixer_params(
+ struct hw_mode_info *hw_mode,
+ const struct crtc_timing *timing,
+ enum view_3d_format view_3d_format)
+{
+ enum timing_3d_format timing_3d_format =
+ dal_ds_translation_get_active_timing_3d_format(
+ timing->timing_3d_format, view_3d_format);
+
+ switch (timing_3d_format) {
+ case TIMING_3D_FORMAT_ROW_INTERLEAVE:
+ hw_mode->stereo_format = HW_STEREO_FORMAT_ROW_INTERLEAVED;
+ hw_mode->stereo_mixer_params.sub_sampling =
+ timing->flags.SUB_SAMPLE_3D;
+ break;
+
+ case TIMING_3D_FORMAT_COLUMN_INTERLEAVE:
+ hw_mode->stereo_format = HW_STEREO_FORMAT_COLUMN_INTERLEAVED;
+ hw_mode->stereo_mixer_params.sub_sampling =
+ timing->flags.SUB_SAMPLE_3D;
+ break;
+
+ case TIMING_3D_FORMAT_PIXEL_INTERLEAVE:
+ hw_mode->stereo_format = HW_STEREO_FORMAT_CHECKER_BOARD;
+ hw_mode->stereo_mixer_params.sub_sampling =
+ timing->flags.SUB_SAMPLE_3D;
+ break;
+
+ default:
+ hw_mode->stereo_format = HW_STEREO_FORMAT_NONE;
+ break;
+ }
+}
+
+enum hw_color_space dal_ds_translation_hw_color_space_from_color_space(
+ enum ds_color_space color_space)
+{
+ enum hw_color_space hw_color_space;
+
+ switch (color_space) {
+ case DS_COLOR_SPACE_SRGB_FULLRANGE:
+ hw_color_space = HW_COLOR_SPACE_SRGB_FULL_RANGE;
+ break;
+ case DS_COLOR_SPACE_SRGB_LIMITEDRANGE:
+ hw_color_space = HW_COLOR_SPACE_SRGB_LIMITED_RANGE;
+ break;
+ case DS_COLOR_SPACE_YPBPR601:
+ hw_color_space = HW_COLOR_SPACE_YPBPR601;
+ break;
+ case DS_COLOR_SPACE_YPBPR709:
+ hw_color_space = HW_COLOR_SPACE_YPBPR709;
+ break;
+ case DS_COLOR_SPACE_YCBCR601:
+ hw_color_space = HW_COLOR_SPACE_YCBCR601;
+ break;
+ case DS_COLOR_SPACE_YCBCR709:
+ hw_color_space = HW_COLOR_SPACE_YCBCR709;
+ break;
+ case DS_COLOR_SPACE_NMVPU_SUPERAA:
+ hw_color_space = HW_COLOR_SPACE_NMVPU_SUPERAA;
+ break;
+ default:
+ hw_color_space = HW_COLOR_SPACE_UNKNOWN;
+ break;
+ }
+ return hw_color_space;
+}
+
+enum ds_color_space dal_ds_translation_color_space_from_hw_color_space(
+ enum hw_color_space hw_color_space)
+{
+ enum ds_color_space color_space;
+
+ switch (hw_color_space) {
+ case HW_COLOR_SPACE_SRGB_FULL_RANGE:
+ color_space = DS_COLOR_SPACE_SRGB_FULLRANGE;
+ break;
+ case HW_COLOR_SPACE_SRGB_LIMITED_RANGE:
+ color_space = DS_COLOR_SPACE_SRGB_LIMITEDRANGE;
+ break;
+ case HW_COLOR_SPACE_YPBPR601:
+ color_space = DS_COLOR_SPACE_YPBPR601;
+ break;
+ case HW_COLOR_SPACE_YPBPR709:
+ color_space = DS_COLOR_SPACE_YPBPR709;
+ break;
+ case HW_COLOR_SPACE_YCBCR601:
+ color_space = DS_COLOR_SPACE_YCBCR601;
+ break;
+ case HW_COLOR_SPACE_YCBCR709:
+ color_space = DS_COLOR_SPACE_YCBCR709;
+ break;
+ case HW_COLOR_SPACE_NMVPU_SUPERAA:
+ color_space = DS_COLOR_SPACE_NMVPU_SUPERAA;
+ break;
+ default:
+ color_space = DS_COLOR_SPACE_UNKNOWN;
+ break;
+ }
+ return color_space;
+}
+
+bool dal_ds_translate_regamma_to_external(
+ const struct ds_regamma_lut *gamma_int,
+ struct ds_regamma_lut *gamma_ext)
+{
+ uint32_t i;
+
+ gamma_ext->flags.u32all = 0;
+ gamma_ext->flags.bits.GAMMA_RAMP_ARRAY =
+ gamma_int->flags.bits.GAMMA_RAMP_ARRAY;
+ gamma_ext->flags.bits.COEFF_FROM_EDID =
+ gamma_int->flags.bits.COEFF_FROM_EDID;
+ gamma_ext->flags.bits.GAMMA_FROM_EDID_EX =
+ gamma_int->flags.bits.GAMMA_FROM_EDID_EX;
+ gamma_ext->flags.bits.GAMMA_FROM_USER =
+ gamma_int->flags.bits.GAMMA_FROM_USER;
+
+ gamma_ext->flags.bits.COEFF_FROM_USER =
+ gamma_int->flags.bits.COEFF_FROM_USER;
+ gamma_ext->flags.bits.COEFF_FROM_EDID =
+ gamma_int->flags.bits.COEFF_FROM_EDID;
+
+ if (gamma_int->flags.bits.GAMMA_RAMP_ARRAY == 1) {
+ gamma_ext->flags.bits.APPLY_DEGAMMA =
+ gamma_int->flags.bits.APPLY_DEGAMMA;
+ for (i = 0 ; i < REGAMMA_RANGE ; i++)
+ gamma_ext->gamma.gamma[i] =
+ gamma_int->gamma.gamma[i];
+ } else {
+ gamma_ext->flags.bits.APPLY_DEGAMMA = 0;
+ for (i = 0; i < COEFF_RANGE ; i++) {
+ gamma_ext->coeff.coeff_a0[i] =
+ gamma_int->coeff.coeff_a0[i];
+ gamma_ext->coeff.coeff_a1[i] =
+ gamma_int->coeff.coeff_a1[i];
+ gamma_ext->coeff.coeff_a2[i] =
+ gamma_int->coeff.coeff_a2[i];
+ gamma_ext->coeff.coeff_a3[i] =
+ gamma_int->coeff.coeff_a3[i];
+ gamma_ext->coeff.gamma[i] =
+ gamma_int->coeff.gamma[i];
+ }
+ }
+ return true;
+
+}
+
+bool dal_ds_translate_regamma_to_internal(
+ const struct ds_regamma_lut *gamma_ext,
+ struct ds_regamma_lut *gamma_int)
+{
+ uint32_t i;
+
+ gamma_int->flags.bits.GAMMA_RAMP_ARRAY =
+ gamma_ext->flags.bits.GAMMA_RAMP_ARRAY;
+ if (gamma_ext->flags.bits.GAMMA_FROM_EDID == 1 ||
+ gamma_ext->flags.bits.GAMMA_FROM_EDID_EX == 1 ||
+ gamma_ext->flags.bits.GAMMA_FROM_USER == 1)
+ return false;
+
+ gamma_int->flags.bits.COEFF_FROM_EDID =
+ gamma_ext->flags.bits.COEFF_FROM_EDID;
+ gamma_int->flags.bits.GAMMA_FROM_EDID_EX =
+ gamma_ext->flags.bits.GAMMA_FROM_EDID_EX;
+ gamma_int->flags.bits.GAMMA_FROM_USER =
+ gamma_ext->flags.bits.GAMMA_FROM_USER;
+
+ if (gamma_ext->flags.bits.COEFF_FROM_USER == 1 &&
+ gamma_ext->flags.bits.COEFF_FROM_EDID == 1)
+ return false;
+
+ gamma_int->flags.bits.COEFF_FROM_USER =
+ gamma_ext->flags.bits.COEFF_FROM_USER;
+ gamma_int->flags.bits.COEFF_FROM_EDID =
+ gamma_ext->flags.bits.COEFF_FROM_EDID;
+
+ if (gamma_ext->flags.bits.GAMMA_RAMP_ARRAY == 1) {
+ gamma_int->flags.bits.APPLY_DEGAMMA =
+ gamma_ext->flags.bits.APPLY_DEGAMMA;
+ for (i = 0 ; i < REGAMMA_RANGE ; i++)
+ gamma_int->gamma.gamma[i] =
+ gamma_ext->gamma.gamma[i];
+ } else {
+ gamma_int->flags.bits.APPLY_DEGAMMA = 0;
+ for (i = 0; i < COEFF_RANGE ; i++) {
+ gamma_int->coeff.coeff_a0[i] =
+ gamma_ext->coeff.coeff_a0[i];
+ gamma_int->coeff.coeff_a1[i] =
+ gamma_ext->coeff.coeff_a1[i];
+ gamma_int->coeff.coeff_a2[i] =
+ gamma_ext->coeff.coeff_a2[i];
+ gamma_int->coeff.coeff_a3[i] =
+ gamma_ext->coeff.coeff_a3[i];
+ gamma_int->coeff.gamma[i] =
+ gamma_ext->coeff.gamma[i];
+ }
+ }
+ return true;
+}
+
+bool dal_ds_translate_regamma_to_hw(
+ const struct ds_regamma_lut *regumma_lut,
+ struct hw_regamma_lut *regamma_lut_hw)
+{
+ bool ret = true;
+ uint32_t i = 0;
+
+ regamma_lut_hw->flags.bits.gamma_ramp_array =
+ regumma_lut->flags.bits.GAMMA_RAMP_ARRAY;
+ regamma_lut_hw->flags.bits.graphics_degamma_srgb =
+ regumma_lut->flags.bits.GRAPHICS_DEGAMMA_SRGB;
+ regamma_lut_hw->flags.bits.overlay_degamma_srgb =
+ regumma_lut->flags.bits.OVERLAY_DEGAMMA_SRGB;
+
+ if (regumma_lut->flags.bits.GAMMA_RAMP_ARRAY == 1) {
+ regamma_lut_hw->flags.bits.apply_degamma =
+ regumma_lut->flags.bits.APPLY_DEGAMMA;
+
+ for (i = 0; i < 256 * 3; i++)
+ regamma_lut_hw->gamma.gamma[i] = regumma_lut->gamma.gamma[i];
+ } else {
+ regamma_lut_hw->flags.bits.apply_degamma = 0;
+
+ for (i = 0; i < 3; i++) {
+ regamma_lut_hw->coeff.a0[i] =
+ regumma_lut->coeff.coeff_a0[i];
+ regamma_lut_hw->coeff.a1[i] =
+ regumma_lut->coeff.coeff_a1[i];
+ regamma_lut_hw->coeff.a2[i] =
+ regumma_lut->coeff.coeff_a2[i];
+ regamma_lut_hw->coeff.a3[i] =
+ regumma_lut->coeff.coeff_a3[i];
+ regamma_lut_hw->coeff.gamma[i] =
+ regumma_lut->coeff.gamma[i];
+ }
+ }
+ return ret;
+}
+
+bool dal_ds_translate_internal_gamut_to_external_parameter(
+ const struct gamut_data *gamut,
+ struct ds_gamut_data *data)
+{
+ if (gamut->option.bits.CUSTOM_GAMUT_SPACE == 0)
+ data->gamut.predefined = gamut->gamut.predefined.u32all;
+ else {
+ data->feature.bits.CUSTOM_GAMUT_SPACE = 0;
+ data->gamut.custom.red_x = gamut->gamut.custom.red_x;
+ data->gamut.custom.red_y = gamut->gamut.custom.red_y;
+
+ data->gamut.custom.green_x = gamut->gamut.custom.green_x;
+ data->gamut.custom.green_y = gamut->gamut.custom.green_y;
+
+ data->gamut.custom.blue_x = gamut->gamut.custom.blue_x;
+ data->gamut.custom.blue_y = gamut->gamut.custom.blue_y;
+ }
+ if (gamut->option.bits.CUSTOM_WHITE_POINT == 0)
+ data->white_point.predefined =
+ gamut->white_point.predefined.u32all;
+ else {
+ data->feature.bits.CUSTOM_WHITE_POINT = 1;
+ data->white_point.custom.white_x =
+ gamut->white_point.custom.white_x;
+ data->white_point.custom.white_y =
+ gamut->white_point.custom.white_y;
+ }
+ return true;
+}
+
+bool dal_ds_translate_gamut_reference(
+ const struct ds_gamut_reference_data *ref,
+ enum adjustment_id *adj_id)
+{
+ if (ref->gamut_ref == DS_GAMUT_REFERENCE_DESTINATION)
+ *adj_id = ADJ_ID_GAMUT_DESTINATION;
+ else {
+ if (ref->gamut_content == DS_GAMUT_CONTENT_GRAPHICS)
+ *adj_id = ADJ_ID_GAMUT_SOURCE_GRPH;
+ else
+ *adj_id = ADJ_ID_GAMUT_SOURCE_OVL;
+ }
+ return true;
+}
diff --git a/drivers/gpu/drm/amd/dal/display_service/ds_translation.h b/drivers/gpu/drm/amd/dal/display_service/ds_translation.h
new file mode 100644
index 000000000000..c314752bfd13
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/ds_translation.h
@@ -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
+ *
+ */
+#ifndef __DAL_DS_TRANSLATION_H__
+#define __DAL_DS_TRANSLATION_H__
+
+#include "adjustment_types_internal.h"
+#include "include/timing_service_types.h"
+#include "include/set_mode_types.h"
+
+/* Translate adjustment value into supported display content type */
+void dal_ds_translation_translate_content_type(uint32_t val,
+ enum display_content_type *support);
+
+/* Get valid 3D format */
+enum timing_3d_format dal_ds_translation_get_active_timing_3d_format(
+ enum timing_3d_format timing_format,
+ enum view_3d_format view_format);
+
+/* Translate timing 3D format to view 3D format*/
+enum view_3d_format dal_ds_translation_3d_format_timing_to_view(
+ enum timing_3d_format timing_format);
+
+void dal_ds_translation_patch_hw_view_for_3d(
+ struct view *view,
+ const struct crtc_timing *timing,
+ enum view_3d_format view_3d_format);
+
+void dal_ds_translation_hw_crtc_timing_from_crtc_timing(
+ struct hw_crtc_timing *hw_timing,
+ const struct crtc_timing *timing,
+ enum view_3d_format view_3d_format,
+ enum signal_type signal);
+
+void dal_ds_translation_setup_hw_stereo_mixer_params(
+ struct hw_mode_info *hw_mode,
+ const struct crtc_timing *timing,
+ enum view_3d_format view_3d_format);
+
+/*enum hw_pixel_format dal_ds_translate_hw_pixel_format_from_pixel_format(
+ const enum pixel_format pf);*/
+
+enum underscan_reason {
+ UNDERSCAN_REASON_PATCH_TIMING,
+ UNDERSCAN_REASON_CHECK_STEP,
+ UNDERSCAN_REASON_SET_ADJUSTMENT,
+ UNDERSCAN_REASON_GET_INFO,
+ UNDERSCAN_REASON_PATCH_TIMING_SET_MODE,
+ UNDERSCAN_REASON_FALL_BACK,
+};
+
+enum hw_color_space dal_ds_translation_hw_color_space_from_color_space(
+ enum ds_color_space color_space);
+
+enum ds_color_space dal_ds_translation_color_space_from_hw_color_space(
+ enum hw_color_space hw_color_space);
+
+bool dal_ds_translate_regamma_to_external(
+ const struct ds_regamma_lut *gamma_int,
+ struct ds_regamma_lut *gamma_ext);
+
+bool dal_ds_translate_regamma_to_internal(
+ const struct ds_regamma_lut *gamma_ext,
+ struct ds_regamma_lut *gamma_int);
+
+bool dal_ds_translate_regamma_to_hw(
+ const struct ds_regamma_lut *regumma_lut,
+ struct hw_regamma_lut *regamma_lut_hw);
+
+bool dal_ds_translate_internal_gamut_to_external_parameter(
+ const struct gamut_data *gamut,
+ struct ds_gamut_data *data);
+
+bool dal_ds_translate_gamut_reference(
+ const struct ds_gamut_reference_data *ref,
+ enum adjustment_id *adj_id);
+
+#endif /* __DAL_DS_TRANSLATION_H__ */
diff --git a/drivers/gpu/drm/amd/dal/display_service/gamma_lut.c b/drivers/gpu/drm/amd/dal/display_service/gamma_lut.c
new file mode 100644
index 000000000000..90af79cde6f6
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/gamma_lut.c
@@ -0,0 +1,391 @@
+/*****************************************************************************\
+ * Module Name: GammaLUT.cpp
+ * Project: DAL 2012 Rearchitecture
+ * Device: EG and later
+ *
+ * Description: Implementation of GammaLUT class
+ *
+ * Copyright (c) 2012 Advanced Micro Devices, Inc. (unpublished)
+ *
+ * All rights reserved. This notice is intended as a precaution against
+ * inadvertent publication and does not imply publication or any waiver
+ * of confidentiality. The year included in the foregoing notice is the
+ * year of creation of the work.
+ *
+ \*****************************************************************************/
+
+#include "dal_services.h"
+#include "display_service/ds_dispatch.h"
+#include "display_service/ds_translation.h"
+#include "display_service/grph_colors_group.h"
+#include "include/hw_sequencer_interface.h"
+#include "include/display_path_interface.h"
+#include "include/adjustment_interface.h"
+#include "gamma_lut.h"
+
+static bool grph_gamma_lut_group_construct(
+ struct grph_gamma_lut_group *grph_gamma_adj,
+ struct grph_gamma_lut_group_init_data *init_data) {
+ if (!init_data)
+ return false;
+
+ grph_gamma_adj->ds = init_data->ds;
+ grph_gamma_adj->hws = init_data->hws;
+ grph_gamma_adj->dal_context = init_data->dal_context;
+
+ return true;
+}
+
+struct grph_gamma_lut_group *dal_gamma_adj_group_create(
+ struct grph_gamma_lut_group_init_data *init_data) {
+ struct grph_gamma_lut_group *grph_gamma_adj = NULL;
+
+ grph_gamma_adj = dal_alloc(sizeof(*grph_gamma_adj));
+
+ if (!grph_gamma_adj)
+ return NULL;
+
+ if (grph_gamma_lut_group_construct(grph_gamma_adj, init_data))
+ return grph_gamma_adj;
+
+ dal_free(grph_gamma_adj);
+
+ return NULL;
+}
+
+static bool update_internal_status(
+ struct ds_dispatch *ds,
+ enum adjustment_id adj_id,
+ const struct raw_gamma_ramp *gamma)
+{
+ bool ret = false;
+ struct ds_adjustment_status *status = NULL;
+
+ if (ds == NULL)
+ return ret;
+
+ switch (adj_id) {
+ case ADJ_ID_GAMMA_RAMP:
+ status = &ds->grph_gamma_adj->status_gamma_ramp;
+ break;
+ case ADJ_ID_DRIVER_REQUESTED_GAMMA:
+ default:
+ break;
+ }
+
+ if (status != NULL) {
+ status->bits.SET_TO_HARDWARE = 1;
+ ret = true;
+ }
+
+ return ret;
+}
+
+enum ds_return dal_grph_gamma_lut_set_adjustment(
+ struct ds_dispatch *ds,
+ const struct display_path *disp_path,
+ const struct path_mode *disp_path_mode,
+ enum adjustment_id adj_id,
+ const struct raw_gamma_ramp *gamma,
+ const struct ds_regamma_lut *regumma_lut) {
+
+ enum ds_return ret = DS_ERROR;
+ struct hw_adjustment_gamma_ramp *hw_gamma_ramp = NULL;
+
+ if (gamma == NULL)
+ return ret;
+
+ if (ds == NULL)
+ return ret;
+
+ do {
+ /* TODO validate to compare if this gamma is already set! */
+ if (disp_path == NULL)
+ break;
+
+ if (!dal_gamma_lut_validate(adj_id, gamma, true))
+ break;
+
+ hw_gamma_ramp = dal_alloc(
+ sizeof(struct hw_adjustment_gamma_ramp));
+
+ if (hw_gamma_ramp == NULL)
+ break;
+
+ if (adj_id == ADJ_ID_GAMMA_RAMP)
+ dal_gamma_lut_set_current_gamma(
+ ds,
+ ADJ_ID_DRIVER_REQUESTED_GAMMA,
+ gamma);
+
+ dal_ds_translate_regamma_to_hw(
+ regumma_lut,
+ &hw_gamma_ramp->regamma);
+
+ if (!dal_gamma_lut_translate_to_hw(
+ ds, disp_path_mode,
+ disp_path,
+ gamma,
+ hw_gamma_ramp))
+ break;
+
+ hw_gamma_ramp->flag.uint = 0;
+ hw_gamma_ramp->flag.bits.config_is_changed = 0;
+
+ if (adj_id == ADJ_ID_GAMMA_RAMP_REGAMMA_UPDATE)
+ hw_gamma_ramp->flag.bits.regamma_update = 1;
+ else
+ hw_gamma_ramp->flag.bits.gamma_update = 1;
+
+ if (dal_hw_sequencer_set_gamma_ramp_adjustment(
+ ds->hwss,
+ disp_path,
+ hw_gamma_ramp) != HWSS_RESULT_OK)
+ break;
+
+ if (adj_id == ADJ_ID_GAMMA_RAMP) {
+ dal_gamma_lut_set_current_gamma(ds, adj_id, gamma);
+ update_internal_status(ds, adj_id, gamma);
+ }
+
+ ret = DS_SUCCESS;
+
+ } while (0);
+
+ dal_free(hw_gamma_ramp);
+ return ret;
+}
+
+bool dal_gamma_lut_validate(
+ enum adjustment_id adj_id,
+ const struct raw_gamma_ramp *gamma,
+ bool validate_all) {
+ if (adj_id != ADJ_ID_DRIVER_REQUESTED_GAMMA
+ && adj_id != ADJ_ID_GAMMA_RAMP
+ && adj_id != ADJ_ID_GAMMA_RAMP_REGAMMA_UPDATE)
+ return false;
+
+ if (!validate_all)
+ return true;
+
+ if (gamma == NULL)
+ return false;
+
+ if (gamma->type != GAMMA_RAMP_TYPE_RGB256
+ && gamma->type != GAMMA_RAMP_TYPE_FIXED_POINT)
+ return false;
+
+ if (gamma->type == GAMMA_RAMP_TYPE_RGB256
+ && gamma->size != sizeof(gamma->rgb_256))
+ return false;
+
+ return true;
+}
+
+bool dal_gamma_lut_translate_to_hw(
+ struct ds_dispatch *ds,
+ const struct path_mode *disp_path_mode,
+ const struct display_path *disp_path,
+ const struct raw_gamma_ramp *gamma_in,
+ struct hw_adjustment_gamma_ramp *gamma_out) {
+ unsigned int i;
+ enum pixel_format pix_format = disp_path_mode->pixel_format;
+ enum ds_color_space color_space = DS_COLOR_SPACE_UNKNOWN;
+
+ uint32_t display_index;
+ struct adj_container *adj_container = NULL;
+
+ if (!disp_path)
+ return false;
+
+ display_index = dal_display_path_get_display_index(disp_path);
+
+ adj_container = dal_ds_dispatch_get_adj_container_for_path(ds,
+ display_index);
+
+ if (gamma_in == NULL)
+ return false;
+
+ /* translate the PixelFormat */
+ gamma_out->surface_pixel_format = pix_format;
+
+ if (gamma_in->type != GAMMA_RAMP_TYPE_RGB256)
+ return false;
+
+ gamma_out->type = HW_GAMMA_RAMP_RBG_256x3x16;
+ gamma_out->size = sizeof(gamma_out->gamma_ramp_rgb256x3x16);
+
+ /* copy the rgb */
+ for (i = 0; i < NUM_OF_RAW_GAMMA_RAMP_RGB_256; i++) {
+ gamma_out->gamma_ramp_rgb256x3x16.red[i] =
+ (unsigned short) (gamma_in->rgb_256[i].red);
+ gamma_out->gamma_ramp_rgb256x3x16.green[i] =
+ (unsigned short) (gamma_in->rgb_256[i].green);
+ gamma_out->gamma_ramp_rgb256x3x16.blue[i] =
+ (unsigned short) (gamma_in->rgb_256[i].blue);
+ }
+
+ /*
+ * logic below builds the color space and it is used for color
+ * adjustments also
+ */
+ color_space = dal_grph_colors_group_get_color_space(
+ ds->grph_colors_adj,
+ &disp_path_mode->mode_timing->crtc_timing,
+ disp_path,
+ adj_container);
+
+ gamma_out->color_space =
+ dal_ds_translation_hw_color_space_from_color_space(color_space);
+
+ return true;
+}
+
+static bool get_parameters(
+ struct ds_dispatch *ds,
+ enum adjustment_id adj_id,
+ struct ds_adjustment_status **adjustment_status,
+ struct raw_gamma_ramp **gamma)
+{
+ struct ds_adjustment_status *status = NULL;
+ struct raw_gamma_ramp *ramp = NULL;
+
+ if (ds == NULL)
+ return false;
+
+ if (ds->grph_gamma_adj == NULL)
+ return false;
+
+ switch (adj_id) {
+ case ADJ_ID_GAMMA_RAMP:
+ status = &ds->grph_gamma_adj->status_gamma_ramp;
+ ramp = &ds->grph_gamma_adj->gamma_ramp;
+ break;
+ case ADJ_ID_DRIVER_REQUESTED_GAMMA:
+ status = &ds->grph_gamma_adj->status_original_ramp;
+ ramp = &ds->grph_gamma_adj->oroginal_ramp;
+ break;
+
+ default:
+ break;
+ }
+
+ if (status != NULL && gamma != NULL) {
+ if (adjustment_status != NULL)
+ *adjustment_status = status;
+
+ if (gamma != NULL)
+ *gamma = ramp;
+
+ return true;
+ }
+
+ return false;
+}
+
+static bool generated_default_gamma_ramp(
+ struct ds_dispatch *ds,
+ enum adjustment_id adj_id)
+{
+ bool ret = false;
+ unsigned int i;
+
+ struct raw_gamma_ramp_rgb *rgb256 = NULL;
+ struct ds_adjustment_status *status = NULL;
+ struct raw_gamma_ramp *gamma = NULL;
+
+ if (ds == NULL)
+ return false;
+
+ switch (adj_id) {
+ case ADJ_ID_GAMMA_RAMP:
+ gamma = &ds->grph_gamma_adj->gamma_ramp;
+ status = &ds->grph_gamma_adj->status_gamma_ramp;
+ rgb256 = ds->grph_gamma_adj->gamma_ramp.rgb_256;
+ ret = true;
+ break;
+ case ADJ_ID_DRIVER_REQUESTED_GAMMA:
+ gamma = &ds->grph_gamma_adj->oroginal_ramp;
+ status = &ds->grph_gamma_adj->status_original_ramp;
+ rgb256 = ds->grph_gamma_adj->oroginal_ramp.rgb_256;
+ ret = true;
+ break;
+ default:
+ break;
+ }
+
+ if (ret) {
+ for (i = 0; i < NUM_OF_RAW_GAMMA_RAMP_RGB_256; ++i) {
+ rgb256[i].red = i << 8;
+ rgb256[i].green = i << 8;
+ rgb256[i].blue = i << 8;
+ }
+ status->val = 0;
+ status->bits.SET_TO_DEFAULT = 1;
+ gamma->type = GAMMA_RAMP_TYPE_RGB256;
+ gamma->size = sizeof(struct raw_gamma_ramp_rgb)
+ * NUM_OF_RAW_GAMMA_RAMP_RGB_256;
+ }
+ return ret;
+}
+
+const struct raw_gamma_ramp *dal_gamma_lut_get_current_gamma(
+ struct ds_dispatch *ds,
+ enum adjustment_id adj_id) {
+ struct ds_adjustment_status *adjustment_status = NULL;
+ struct raw_gamma_ramp *gamma = NULL;
+
+ if (ds == NULL)
+ return NULL;
+
+ if (!dal_gamma_lut_validate(adj_id, gamma, false))
+ return NULL;
+
+ if (get_parameters(ds, adj_id, &adjustment_status, &gamma))
+ return gamma;
+
+ if (adjustment_status->bits.SET_FROM_EXTERNAL == 0)
+ if (generated_default_gamma_ramp(ds, adj_id))
+ return gamma;
+
+ return gamma;
+}
+
+bool dal_gamma_lut_set_current_gamma(struct ds_dispatch *ds,
+ enum adjustment_id adj_id,
+ const struct raw_gamma_ramp *gamma)
+{
+ struct ds_adjustment_status *adjustment_status = NULL;
+ struct raw_gamma_ramp *ramp = NULL;
+
+ if (!dal_gamma_lut_validate(adj_id, gamma, true))
+ return false;
+
+ if (!get_parameters(ds, adj_id, &adjustment_status, &ramp))
+ return false;
+
+ dal_memmove(ramp, gamma, sizeof(struct raw_gamma_ramp));
+
+ /* new external gamma was set , reset to 0 default flag */
+ adjustment_status->bits.SET_TO_DEFAULT = 0;
+ /* new external gamma was set , raise this flag */
+ adjustment_status->bits.SET_FROM_EXTERNAL = 1;
+ /* new external gamma was set , raise this flag */
+ adjustment_status->bits.SET_TO_HARDWARE = 0;
+
+ return true;
+
+}
+static void destruct(struct grph_gamma_lut_group *gamma_adj)
+{
+}
+
+void dal_grph_gamma_adj_group_destroy(
+ struct grph_gamma_lut_group **grph_gamma_adj) {
+ if (grph_gamma_adj == NULL || *grph_gamma_adj == NULL)
+ return;
+
+ destruct(*grph_gamma_adj);
+ dal_free(*grph_gamma_adj);
+ *grph_gamma_adj = NULL;
+}
diff --git a/drivers/gpu/drm/amd/dal/display_service/gamma_lut.h b/drivers/gpu/drm/amd/dal/display_service/gamma_lut.h
new file mode 100644
index 000000000000..2c050c92a46a
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/gamma_lut.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2014 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_GAMMA_LUT_H__
+#define __DAL_GAMMA_LUT_H__
+
+#include "adjustment_types_internal.h"
+#include "include/display_service_types.h"
+
+struct ds_dispatch;
+struct grph_colors_group;
+struct crtc_timing;
+struct display_path;
+struct adj_container;
+
+struct grph_gamma_lut_group {
+ struct ds_dispatch *ds;
+ struct hw_sequencer *hws;
+ struct dal_context *dal_context;
+ struct ds_adjustment_status status_gamma_ramp;
+ struct ds_adjustment_status status_original_ramp;
+ struct raw_gamma_ramp gamma_ramp;
+ struct raw_gamma_ramp oroginal_ramp;
+};
+
+struct grph_gamma_lut_group_init_data {
+ struct ds_dispatch *ds;
+ struct hw_sequencer *hws;
+ struct dal_context *dal_context;
+};
+
+struct grph_gamma_lut_group *dal_gamma_adj_group_create(
+ struct grph_gamma_lut_group_init_data *init_data);
+
+void dal_grph_gamma_adj_group_destroy(
+ struct grph_gamma_lut_group **grph_gamma_adj);
+
+
+enum ds_return dal_grph_gamma_lut_set_adjustment(
+ struct ds_dispatch *ds,
+ const struct display_path *disp_path,
+ const struct path_mode *disp_path_mode,
+ enum adjustment_id adj_id,
+ const struct raw_gamma_ramp *gamma,
+ const struct ds_regamma_lut *regumma_lut);
+
+bool dal_gamma_lut_validate(
+ enum adjustment_id adj_id,
+ const struct raw_gamma_ramp *gamma,
+ bool validate_all);
+
+bool dal_gamma_lut_translate_to_hw(
+ struct ds_dispatch *ds,
+ const struct path_mode *disp_path_mode,
+ const struct display_path *disp_path,
+ const struct raw_gamma_ramp *gamma_in,
+ struct hw_adjustment_gamma_ramp *gamma_out);
+
+const struct raw_gamma_ramp *dal_gamma_lut_get_current_gamma(
+ struct ds_dispatch *ds,
+ enum adjustment_id adj_id);
+
+bool dal_gamma_lut_set_current_gamma(struct ds_dispatch *ds,
+ enum adjustment_id adj_id,
+ const struct raw_gamma_ramp *gamma);
+
+#endif /* __DAL_GAMMA_LUT_H__ */
diff --git a/drivers/gpu/drm/amd/dal/display_service/gamut_space.c b/drivers/gpu/drm/amd/dal/display_service/gamut_space.c
new file mode 100644
index 000000000000..08207d805eff
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/gamut_space.c
@@ -0,0 +1,1140 @@
+/*
+ * Copyright 2015 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/fixed31_32.h"
+
+#include "gamut_space.h"
+
+const struct gamut_space_entry gamut_array[] = {
+
+ {1, 6400, 3300, 3000, 6000, 1500, 600, 180000, 4500, 99, 99, 2200 },
+ {2, 6400, 3300, 2900, 6000, 1500, 600, 180000, 4500, 99, 99, 2200 },
+ {4, 6400, 3300, 2100, 7100, 1500, 600, 180000, 4500, 99, 99, 2200 },
+ {8, 6400, 3300, 3000, 6000, 1500, 600, 31308, 12920, 55, 55, 2400 }
+};
+
+const struct white_point_coodinates_entry white_point_array[] = {
+ {1, 3473, 3561 },
+ {2, 3127, 3290 },
+ {4, 3022, 3129 },
+ {8, 2866, 2950 }
+};
+
+void dal_gamut_space_reset_gamut(
+ struct gamut_data *data,
+ bool gamut,
+ bool white_point)
+{
+ if (gamut == true) {
+ data->option.bits.CUSTOM_GAMUT_SPACE = 0;
+ dal_memset(&data->gamut, 0, sizeof(data->gamut));
+ }
+ if (white_point) {
+ data->option.bits.CUSTOM_WHITE_POINT = 0;
+ dal_memset(&data->white_point, 0, sizeof(data->white_point));
+ }
+}
+static void set_regamma_support(
+ struct gamut_parameter *gamut,
+ struct gamut_data *gamut_dst,
+ union update_color_flags *flags)
+{
+ struct color_space_coodinates csc = {0};
+ union ds_gamut_spaces
+ predefined_coordinates = {0};
+ union ds_gamut_spaces
+ predefined_coefficients = {0};
+
+ if (gamut->gamut_dst.option.bits.CUSTOM_GAMUT_SPACE == 0) {
+ if (gamut->regamma.flags.bits.GAMMA_RAMP_ARRAY == 1) {
+ if (!dal_gamut_space_find_predefined_gamut(
+ gamut->gamut_dst.gamut.predefined,
+ &csc,
+ NULL))
+ return;
+ gamut->gamut_dst.option.bits.CUSTOM_GAMUT_SPACE = 1;
+ gamut->gamut_dst.gamut.custom.red_x = csc.red_x;
+ gamut->gamut_dst.gamut.custom.red_y = csc.red_y;
+ gamut->gamut_dst.gamut.custom.green_x = csc.green_x;
+ gamut->gamut_dst.gamut.custom.green_y = csc.green_y;
+ gamut->gamut_dst.gamut.custom.blue_x = csc.blue_x;
+ gamut->gamut_dst.gamut.custom.blue_y = csc.blue_y;
+ flags->bits.GAMUT_DST = 1;
+ } else {
+ bool found_coefficients =
+ dal_gamut_space_find_regamma_coefficients(
+ &gamut->regamma.coeff,
+ &gamut_dst->gamut.predefined);
+ if (found_coefficients == false ||
+ gamut->gamut_dst.gamut.predefined.u32all !=
+ gamut_dst->gamut.predefined.u32all) {
+ if (!dal_gamut_space_find_predefined_gamut(
+ gamut->gamut_dst.gamut.predefined,
+ &csc,
+ NULL))
+ return;
+
+ gamut->gamut_dst.option.bits.CUSTOM_GAMUT_SPACE
+ = 1;
+ gamut->gamut_dst.gamut.custom.red_x =
+ csc.red_x;
+ gamut->gamut_dst.gamut.custom.red_y =
+ csc.red_y;
+ gamut->gamut_dst.gamut.custom.green_x =
+ csc.green_x;
+ gamut->gamut_dst.gamut.custom.green_y =
+ csc.green_y;
+ gamut->gamut_dst.gamut.custom.blue_x =
+ csc.blue_x;
+ gamut->gamut_dst.gamut.custom.blue_y =
+ csc.blue_y;
+ flags->bits.GAMUT_DST = 1;
+ }
+ }
+ } else if (gamut->gamut_dst.option.bits.CUSTOM_GAMUT_SPACE == 1) {
+ if (gamut->regamma.flags.bits.GAMMA_RAMP_ARRAY == 0 &&
+ gamut->regamma.flags.bits.COEFF_FROM_USER == 1) {
+ if (!dal_gamut_space_find_color_coordinates(
+ &csc,
+ &predefined_coordinates))
+ return;
+ if (!dal_gamut_space_find_regamma_coefficients(
+ &gamut->regamma.coeff,
+ &predefined_coefficients))
+ return;
+ if (predefined_coordinates.u32all !=
+ predefined_coefficients.u32all)
+ return;
+
+ gamut->gamut_dst.option.bits.CUSTOM_GAMUT_SPACE = 0;
+ gamut->gamut_dst.gamut.predefined.u32all =
+ predefined_coordinates.u32all;
+ flags->bits.GAMUT_DST = 1;
+
+ }
+ }
+}
+
+
+bool dal_gamut_space_update_gamut(
+ struct gamut_parameter *gamut,
+ bool set_regamma,
+ union update_color_flags *flags)
+{
+ struct gamut_data gamut_dst = {{0} };
+
+ if (gamut->source != GAMUT_SPACE_SOURCE_USER_GAMUT)
+ return true;
+
+ if (set_regamma == true)
+ set_regamma_support(gamut, &gamut_dst, flags);
+ else {
+ if (gamut->gamut_dst.option.bits.CUSTOM_GAMUT_SPACE
+ == 1)
+ return true;
+
+ if (gamut->regamma.flags.bits.GAMMA_RAMP_ARRAY == 1)
+ return true;
+
+ if (gamut->regamma.flags.bits.COEFF_FROM_USER == 0)
+ return true;
+
+ if (gamut->regamma.flags.bits.GAMMA_FROM_USER == 0)
+ return true;
+ {
+ struct ds_regamma_coefficients_ex
+ gamma_coeff = {{0} };
+ union update_color_flags aflags = {0};
+
+ if (!dal_gamut_space_find_predefined_gamut(
+ gamut->gamut_dst.gamut.predefined,
+ NULL,
+ &gamma_coeff))
+ return true;
+
+ if (!dal_gamut_space_is_equal_gamma_coefficients(
+ &gamut->regamma.coeff,
+ &gamma_coeff,
+ &aflags)) {
+ dal_memmove(&gamut->regamma.coeff,
+ &gamma_coeff,
+ sizeof(gamut->regamma.coeff));
+ flags->bits.REGAMMA = 1;
+ }
+ }
+ }
+ return true;
+}
+
+bool dal_gamut_space_find_predefined_gamut(
+ union ds_gamut_spaces predefine,
+ struct color_space_coodinates *csc,
+ struct ds_regamma_coefficients_ex *gamma_coeff)
+{
+ bool ret = false;
+ const struct gamut_space_entry *p;
+ uint32_t const_size;
+ uint32_t i;
+
+ const_size = ARRAY_SIZE(gamut_array);
+
+ for (p = gamut_array ; p < &gamut_array[const_size]; p++) {
+ if (p->index == predefine.u32all) {
+ if (csc != NULL) {
+ csc->red_x = p->red_x;
+ csc->red_y = p->red_y;
+ csc->green_x = p->green_x;
+ csc->green_y = p->green_y;
+ csc->blue_x = p->blue_x;
+ csc->blue_y = p->blue_y;
+ }
+ if (gamma_coeff != NULL) {
+ for (i = 0 ; i < COEFF_RANGE ; i++) {
+ gamma_coeff->coeff_a0[i] = p->a0;
+ gamma_coeff->coeff_a1[i] = p->a1;
+ gamma_coeff->coeff_a2[i] = p->a2;
+ gamma_coeff->coeff_a3[i] = p->a3;
+ gamma_coeff->gamma[i] = p->gamma;
+ }
+ }
+ ret = true;
+ break;
+ }
+ }
+ return ret;
+}
+
+bool dal_gamut_space_find_regamma_coefficients(
+ struct ds_regamma_coefficients_ex *coeff,
+ union ds_gamut_spaces *predefine)
+{
+ bool ret = false;
+ const struct gamut_space_entry *p;
+ uint32_t const_size;
+
+ if (coeff->coeff_a0[0] != coeff->coeff_a0[1] ||
+ coeff->coeff_a0[0] != coeff->coeff_a0[2])
+ return false;
+
+ if (coeff->coeff_a1[0] != coeff->coeff_a1[1] ||
+ coeff->coeff_a1[0] != coeff->coeff_a1[2])
+ return false;
+
+ if (coeff->coeff_a2[0] != coeff->coeff_a2[1] ||
+ coeff->coeff_a2[0] != coeff->coeff_a2[2])
+ return false;
+
+ if (coeff->coeff_a3[0] != coeff->coeff_a3[1] ||
+ coeff->coeff_a3[0] != coeff->coeff_a3[2])
+ return false;
+
+ if (coeff->gamma[0] != coeff->gamma[1] ||
+ coeff->gamma[0] != coeff->gamma[2])
+ return false;
+
+ const_size = ARRAY_SIZE(gamut_array);
+
+ for (p = gamut_array; p < &gamut_array[const_size]; p++) {
+ if (p->a0 == coeff->coeff_a0[0] &&
+ p->a1 == coeff->coeff_a1[0] &&
+ p->a2 == coeff->coeff_a2[0] &&
+ p->a3 == coeff->coeff_a3[0] &&
+ p->gamma == coeff->gamma[0]) {
+
+ predefine->u32all = p->index;
+ ret = true;
+ break;
+ }
+ }
+ return ret;
+}
+
+bool dal_gamut_space_find_color_coordinates(
+ struct color_space_coodinates *csc,
+ union ds_gamut_spaces *predefine)
+{
+ bool ret = false;
+ const struct gamut_space_entry *p;
+ uint32_t const_size;
+
+ const_size = ARRAY_SIZE(gamut_array);
+ for (p = gamut_array; p < &gamut_array[const_size]; p++) {
+ if (p->red_x == csc->red_x &&
+ p->red_y == csc->red_y &&
+ p->green_x == csc->green_x &&
+ p->green_y == csc->green_y &&
+ p->blue_x == csc->blue_x &&
+ p->blue_y == csc->blue_y){
+
+ predefine->u32all = p->index;
+ ret = true;
+ break;
+ }
+ }
+ return ret;
+}
+
+bool dal_gamut_space_is_equal_gamma_coefficients(
+ struct ds_regamma_coefficients_ex *coeff,
+ struct ds_regamma_coefficients_ex *coeff_custom,
+ union update_color_flags *flags)
+{
+ bool ret = true;
+ uint32_t i;
+
+ for (i = 0 ; i < COEFF_RANGE ; i++) {
+ if (coeff->gamma[i] != coeff_custom->gamma[i]) {
+ flags->bits.REGAMMA = 1;
+ ret = false;
+ break;
+ }
+ if (coeff->coeff_a0[i] != coeff_custom->coeff_a0[i]) {
+ flags->bits.REGAMMA = 1;
+ ret = false;
+ break;
+ }
+ if (coeff->coeff_a1[i] != coeff_custom->coeff_a1[i]) {
+ flags->bits.REGAMMA = 1;
+ ret = false;
+ break;
+ }
+ if (coeff->coeff_a2[i] != coeff_custom->coeff_a2[i]) {
+ flags->bits.REGAMMA = 1;
+ ret = false;
+ break;
+ }
+ if (coeff->coeff_a3[i] != coeff_custom->coeff_a3[i]) {
+ flags->bits.REGAMMA = 1;
+ ret = false;
+ break;
+ }
+ }
+ return ret;
+}
+
+bool dal_gamut_space_setup_default_gamut(
+ enum adjustment_id adj_id,
+ struct gamut_data *data,
+ bool gamut,
+ bool white_point)
+{
+ if (gamut == true) {
+ data->option.bits.CUSTOM_GAMUT_SPACE = 0;
+ dal_memset(&data->gamut, 0, sizeof(data->gamut));
+ data->gamut.predefined.bits.GAMUT_SPACE_CIERGB = 1;
+ }
+ if (white_point == true) {
+ data->option.bits.CUSTOM_WHITE_POINT = 0;
+ dal_memset(&data->white_point, 0, sizeof(data->white_point));
+ data->white_point.predefined.bits.GAMUT_WHITE_POINT_6500 = 1;
+ }
+ return true;
+}
+
+bool dal_gamut_space_build_gamut_space_matrix(
+ struct gamut_parameter *gamut,
+ uint32_t temp_matrix[GAMUT_MATRIX_SIZE_3X3],
+ struct ds_regamma_lut *regamma,
+ union update_color_flags *flags)
+{
+ struct gamut_matrixs matrix;
+ bool ret = false;
+
+ matrix.rgb_coeff_dst = NULL;
+
+ if (gamut->source == GAMUT_SPACE_SOURCE_DEFAULT) {
+ ret = dal_gamut_space_build_default_unity_matrix(
+ temp_matrix, regamma);
+ goto check_result;
+
+ }
+ if (gamut->source != GAMUT_SPACE_SOURCE_EDID &&
+ gamut->source != GAMUT_SPACE_SOURCE_USER_GAMUT)
+ goto check_result;
+
+ if (!dal_gamut_space_allocate_matrix(&matrix))
+ goto check_result;
+
+ if (gamut->source == GAMUT_SPACE_SOURCE_EDID) {
+ if (!dal_gamut_space_build_gamut_matrix(
+ matrix.rgb_coeff_src,
+ matrix.white_coeff_src,
+ regamma,
+ flags,
+ &gamut->regamma,
+ &gamut->gamut_src,
+ true))
+ goto check_result;
+
+ if (!dal_gamut_build_edid_matrix(
+ regamma,
+ flags,
+ gamut->color_charact.gamma,
+ matrix.rgb_coeff_dst,
+ matrix.white_coeff_dst,
+ gamut->color_charact.color_charact))
+ goto check_result;
+
+ } else if (gamut->source == GAMUT_SPACE_SOURCE_USER_GAMUT) {
+ if (!dal_gamut_space_build_gamut_matrix(
+ matrix.rgb_coeff_dst,
+ matrix.white_coeff_dst,
+ regamma,
+ flags,
+ &gamut->regamma,
+ &gamut->gamut_dst,
+ false))
+ goto check_result;
+
+ if (!dal_gamut_space_build_gamut_matrix(
+ matrix.rgb_coeff_src,
+ matrix.white_coeff_src,
+ regamma,
+ flags,
+ &gamut->regamma,
+ &gamut->gamut_src,
+ true))
+ goto check_result;
+ }
+ if (!dal_gamut_space_gamut_to_color_matrix(
+ matrix.rgb_coeff_dst,
+ matrix.white_coeff_dst,
+ matrix.rgb_coeff_src,
+ matrix.white_coeff_src,
+ true,
+ temp_matrix))
+ goto check_result;
+
+ ret = true;
+
+check_result:
+
+ dal_gamut_space_dellocate_matrix(&matrix);
+
+ if (ret == false) {
+ ret = dal_gamut_space_build_default_unity_matrix(
+ temp_matrix, regamma);
+ flags->bits.REGAMMA = 1;
+ }
+ return ret;
+}
+
+bool dal_gamut_space_build_default_unity_matrix(
+ uint32_t temp_matrix[GAMUT_MATRIX_SIZE_3X3],
+ struct ds_regamma_lut *regamma)
+{
+ uint32_t i;
+ union ds_gamut_spaces def = {0 };
+
+ if (!temp_matrix || !regamma)
+ return false;
+
+ for (i = 0 ; i < GAMUT_MATRIX_SIZE_3X3 ; i++) {
+ if (i == 0 || i == 4 || i == 8)
+ temp_matrix[i] = GAMUT_DIVIDER;
+ else
+ temp_matrix[i] = 0;
+ }
+ def.u32all = 0;
+ def.bits.GAMUT_SPACE_CIERGB = 1;
+ regamma->flags.u32all = 0;
+
+ if (!dal_gamut_space_find_predefined_gamut(
+ def,
+ NULL,
+ &regamma->coeff))
+ return false;
+
+ return true;
+}
+
+bool dal_gamut_space_allocate_matrix(
+ struct gamut_matrixs *matrix)
+{
+ uint32_t size_of_allocation;
+
+ size_of_allocation = (sizeof(struct fixed31_32) * 3 +
+ sizeof(struct fixed31_32) * 9) * 2;
+
+ matrix->rgb_coeff_dst = dal_alloc(size_of_allocation);
+
+ if (!matrix->rgb_coeff_dst)
+ return false;
+ matrix->white_coeff_dst = matrix->rgb_coeff_dst + 9;
+ matrix->rgb_coeff_src = matrix->white_coeff_dst + 3;
+ matrix->white_coeff_src = matrix->rgb_coeff_src + 9;
+
+ return true;
+}
+
+void dal_gamut_space_dellocate_matrix(
+ struct gamut_matrixs *matrix)
+{
+ if (matrix->rgb_coeff_dst != NULL) {
+ dal_free(matrix->rgb_coeff_dst);
+ matrix->rgb_coeff_dst = NULL;
+ }
+}
+
+bool dal_gamut_space_build_gamut_matrix(
+ struct fixed31_32 *rgb,
+ struct fixed31_32 *white,
+ struct ds_regamma_lut *regamma,
+ union update_color_flags *flags,
+ struct ds_regamma_lut *custom_regamma,
+ struct gamut_data *data,
+ bool is_source)
+{
+ struct color_space_coodinates csc = {0 };
+ struct color_characteristic fcsc;
+ struct ds_regamma_coefficients_ex coeff;
+
+ dal_memmove(regamma, custom_regamma, sizeof(*regamma));
+ if (data->option.bits.CUSTOM_GAMUT_SPACE == 1) {
+ csc.red_x = data->gamut.custom.red_x;
+ csc.red_y = data->gamut.custom.red_y;
+ csc.green_x = data->gamut.custom.green_x;
+ csc.green_y = data->gamut.custom.green_y;
+ csc.blue_x = data->gamut.custom.blue_x;
+ csc.blue_y = data->gamut.custom.blue_y;
+ } else {
+ dal_memset(&coeff, 0, sizeof(coeff));
+ if (!dal_gamut_space_find_predefined_gamut(
+ data->gamut.predefined,
+ &csc,
+ &coeff))
+ return false;
+
+ if (custom_regamma->flags.bits.GAMMA_RAMP_ARRAY
+ == 0) {
+ regamma->coeff = coeff;
+ dal_gamut_space_is_equal_gamma_coefficients(
+ &coeff,
+ &custom_regamma->coeff,
+ flags);
+ regamma->flags.bits.GAMMA_FROM_USER = 1;
+ regamma->flags.bits.GAMMA_FROM_EDID = 0;
+ regamma->flags.bits.GAMMA_FROM_EDID_EX = 0;
+ }
+ }
+ if (data->option.bits.CUSTOM_WHITE_POINT == 1) {
+ csc.white_x = data->white_point.custom.white_x;
+ csc.white_y = data->white_point.custom.white_y;
+
+ } else {
+ if (!dal_gamut_space_find_predefined_white_point(
+ data->white_point.predefined,
+ &csc))
+ return false;
+ }
+
+ fcsc.red_x = dal_fixed31_32_div_int(
+ dal_fixed31_32_from_int(
+ (int64_t)csc.red_x), GAMUT_DIVIDER);
+
+ fcsc.red_y = dal_fixed31_32_div_int(
+ dal_fixed31_32_from_int(
+ (int64_t)csc.red_y), GAMUT_DIVIDER);
+
+ fcsc.green_x = dal_fixed31_32_div_int(
+ dal_fixed31_32_from_int(
+ (int64_t)csc.green_x), GAMUT_DIVIDER);
+
+ fcsc.green_y = dal_fixed31_32_div_int(
+ dal_fixed31_32_from_int(
+ (int64_t)csc.green_y), GAMUT_DIVIDER);
+
+ fcsc.blue_x = dal_fixed31_32_div_int(
+ dal_fixed31_32_from_int(
+ (int64_t)csc.blue_x), GAMUT_DIVIDER);
+
+ fcsc.blue_y = dal_fixed31_32_div_int(
+ dal_fixed31_32_from_int(
+ (int64_t)csc.blue_y), GAMUT_DIVIDER);
+
+ fcsc.white_x = dal_fixed31_32_div_int(
+ dal_fixed31_32_from_int(
+ (int64_t)csc.white_x), GAMUT_DIVIDER);
+
+ fcsc.white_y = dal_fixed31_32_div_int(
+ dal_fixed31_32_from_int(
+ (int64_t)csc.white_y), GAMUT_DIVIDER);
+
+ if (!dal_gamut_space_build_chromaticity_matrix(
+ rgb, white, &fcsc))
+ return false;
+
+ return true;
+}
+
+bool dal_gamut_build_edid_matrix(
+ struct ds_regamma_lut *regamma,
+ union update_color_flags *flags,
+ uint32_t edid_gamma,
+ struct fixed31_32 *rgb,
+ struct fixed31_32 *white,
+ uint8_t pa[EDID_GAMUT_COORDINATES])
+{
+ struct color_characteristic pm = {{0} };
+
+ dal_gamut_space_convert_edid_format_color_charact(
+ pa, &pm);
+
+ if (!dal_gamut_space_build_chromaticity_matrix(
+ rgb, white, &pm))
+ return false;
+ return true;
+}
+
+bool dal_gamut_space_build_chromaticity_matrix(
+ struct fixed31_32 *rgb,
+ struct fixed31_32 *white,
+ struct color_characteristic *pm)
+{
+
+ if (pm->red_y.value == 0 || pm->green_y.value == 0 ||
+ pm->blue_y.value == 0 || pm->white_y.value == 0)
+ return false;
+
+ rgb[0] = dal_fixed31_32_div(
+ pm->red_x, pm->red_y);
+ rgb[1] = dal_fixed31_32_one;
+ rgb[2] = dal_fixed31_32_div(
+ dal_fixed31_32_sub(
+ dal_fixed31_32_sub(
+ dal_fixed31_32_one,
+ pm->red_x),
+ pm->red_y),
+ pm->red_y);
+
+ rgb[3] = dal_fixed31_32_div(
+ pm->green_x, pm->green_y);
+ rgb[4] = dal_fixed31_32_one;
+ rgb[5] = dal_fixed31_32_div(
+ dal_fixed31_32_sub(
+ dal_fixed31_32_sub(
+ dal_fixed31_32_one,
+ pm->green_x),
+ pm->green_y),
+ pm->green_y);
+
+ rgb[6] = dal_fixed31_32_div(
+ pm->blue_x, pm->blue_y);
+ rgb[7] = dal_fixed31_32_one;
+ rgb[8] = dal_fixed31_32_div(
+ dal_fixed31_32_sub(
+ dal_fixed31_32_sub(
+ dal_fixed31_32_one,
+ pm->blue_x),
+ pm->blue_y),
+ pm->blue_y);
+
+ white[0] = dal_fixed31_32_div(
+ pm->white_x, pm->white_y);
+ white[1] = dal_fixed31_32_one;
+ white[2] = dal_fixed31_32_div(
+ dal_fixed31_32_sub(
+ dal_fixed31_32_sub(
+ dal_fixed31_32_one,
+ pm->white_x),
+ pm->white_y),
+ pm->white_y);
+
+ return true;
+}
+
+bool dal_gamut_space_gamut_to_color_matrix(
+ struct fixed31_32 *xyz_of_rgb,
+ struct fixed31_32 *xyz_of_white,
+ struct fixed31_32 *ref_xyz_of_rgb,
+ struct fixed31_32 *ref_xyz_of_white,
+ bool invert,
+ uint32_t temp_matrix[GAMUT_MATRIX_SIZE_3X3])
+{
+ uint32_t i;
+ bool ret = false;
+ struct fixed31_32 *xyz_to_rgb_temp;
+ struct fixed31_32 *xyz_to_rgb_final;
+ struct gamut_calculation_matrix matrix;
+
+ matrix.transposed = NULL;
+
+ if (!dal_gamut_space_allocate_calculation_matrix(
+ &matrix))
+ return false;
+
+ matrix.xyz_of_white_ref[0] = ref_xyz_of_white[0];
+ matrix.xyz_of_white_ref[1] = ref_xyz_of_white[1];
+ matrix.xyz_of_white_ref[2] = ref_xyz_of_white[2];
+
+ matrix.xyz_of_rgb_ref[0] = ref_xyz_of_rgb[0];
+ matrix.xyz_of_rgb_ref[1] = ref_xyz_of_rgb[1];
+ matrix.xyz_of_rgb_ref[2] = ref_xyz_of_rgb[2];
+ matrix.xyz_of_rgb_ref[3] = ref_xyz_of_rgb[3];
+ matrix.xyz_of_rgb_ref[4] = ref_xyz_of_rgb[4];
+ matrix.xyz_of_rgb_ref[5] = ref_xyz_of_rgb[5];
+ matrix.xyz_of_rgb_ref[6] = ref_xyz_of_rgb[6];
+ matrix.xyz_of_rgb_ref[7] = ref_xyz_of_rgb[7];
+ matrix.xyz_of_rgb_ref[8] = ref_xyz_of_rgb[8];
+
+ for (i = 0; i < GAMUT_MATRIX_SIZE_3X3 ; i++) {
+ if (i == 0 || i == 4 || i == 8)
+ temp_matrix[i] = GAMUT_DIVIDER;
+ else
+ temp_matrix[i] = 0;
+ }
+ if (invert) {
+ xyz_to_rgb_temp =
+ matrix.xyz_to_rgb_custom;
+ xyz_to_rgb_final =
+ matrix.xyz_to_rgb_ref;
+ } else {
+ xyz_to_rgb_temp =
+ matrix.xyz_to_rgb_ref;
+ xyz_to_rgb_final =
+ matrix.xyz_to_rgb_custom;
+ }
+ dal_gamut_space_transpose_matrix(
+ matrix.xyz_of_rgb_ref,
+ 3,
+ 3,
+ matrix.transposed);
+ if (!dal_gamut_space_calculate_xyz_to_rgb_M3x3(
+ matrix.transposed,
+ matrix.xyz_of_white_ref,
+ matrix.xyz_to_rgb_ref))
+ goto result;
+
+ dal_gamut_space_transpose_matrix(
+ xyz_of_rgb,
+ 3,
+ 3,
+ matrix.transposed);
+ if (!dal_gamut_space_calculate_xyz_to_rgb_M3x3(
+ matrix.transposed,
+ xyz_of_white,
+ matrix.xyz_to_rgb_custom))
+ goto result;
+
+ if (!dal_gamut_space_compute_inverse_matrix_3x3(
+ xyz_to_rgb_temp,
+ matrix.rgb_to_xyz_final))
+ goto result;
+
+ dal_gamut_space_multiply_matrices(
+ matrix.result,
+ matrix.rgb_to_xyz_final,
+ xyz_to_rgb_final,
+ 3,
+ 3,
+ 3);
+ for (i = 0; i < GAMUT_MATRIX_SIZE_3X3 ; i++)
+ temp_matrix[i] = (uint32_t)dal_fixed31_32_round(
+ dal_fixed31_32_abs(
+ dal_fixed31_32_mul_int(
+ matrix.result[i], GAMUT_DIVIDER)));
+ ret = true;
+
+result:
+ dal_gamut_space_deallocate_calculation_matrix(
+ &matrix);
+ return ret;
+
+}
+struct fixed31_32 dal_gamut_space_find_3x3_det(
+ struct fixed31_32 *m)
+{
+ struct fixed31_32 det;
+ struct fixed31_32 a1;
+ struct fixed31_32 a2;
+ struct fixed31_32 a3;
+
+ a1 = dal_fixed31_32_mul(m[0],
+ dal_fixed31_32_sub(
+ dal_fixed31_32_mul(m[4], m[8]),
+ dal_fixed31_32_mul(m[5], m[7])));
+
+ a2 = dal_fixed31_32_mul(m[1],
+ dal_fixed31_32_sub(
+ dal_fixed31_32_mul(m[3], m[8]),
+ dal_fixed31_32_mul(m[5], m[6])));
+
+ a3 = dal_fixed31_32_mul(m[2],
+ dal_fixed31_32_sub(
+ dal_fixed31_32_mul(m[3], m[7]),
+ dal_fixed31_32_mul(m[4], m[6])));
+
+ det = dal_fixed31_32_add(
+ dal_fixed31_32_sub(a1, a2),
+ a3);
+
+ return det;
+}
+bool dal_gamut_space_compute_inverse_matrix_3x3(
+ struct fixed31_32 *m,
+ struct fixed31_32 *im)
+{
+ struct fixed31_32 determinant;
+ struct fixed31_32 neg;
+
+ determinant = dal_gamut_space_find_3x3_det(m);
+
+ if (determinant.value == 0)
+ return false;
+
+ im[0] = dal_fixed31_32_div(
+ dal_fixed31_32_sub(
+ dal_fixed31_32_mul(m[4], m[8]),
+ dal_fixed31_32_mul(m[5], m[7])),
+ determinant);
+ neg = dal_fixed31_32_neg(dal_fixed31_32_one);
+
+ im[1] = dal_fixed31_32_div(
+ dal_fixed31_32_mul(
+ dal_fixed31_32_sub(
+ dal_fixed31_32_mul(m[1], m[8]),
+ dal_fixed31_32_mul(m[2], m[7])),
+ neg),
+ determinant);
+
+ im[2] = dal_fixed31_32_div(
+ dal_fixed31_32_sub(
+ dal_fixed31_32_mul(m[1], m[5]),
+ dal_fixed31_32_mul(m[2], m[4])),
+ determinant);
+
+ im[3] = dal_fixed31_32_div(
+ dal_fixed31_32_mul(
+ dal_fixed31_32_sub(
+ dal_fixed31_32_mul(m[3], m[8]),
+ dal_fixed31_32_mul(m[5], m[6])),
+ neg),
+ determinant);
+
+ im[4] = dal_fixed31_32_div(
+ dal_fixed31_32_sub(
+ dal_fixed31_32_mul(m[0], m[8]),
+ dal_fixed31_32_mul(m[2], m[6])),
+ determinant);
+
+ im[5] = dal_fixed31_32_div(
+ dal_fixed31_32_mul(
+ dal_fixed31_32_sub(
+ dal_fixed31_32_mul(m[0], m[5]),
+ dal_fixed31_32_mul(m[2], m[3])),
+ neg),
+ determinant);
+
+ im[6] = dal_fixed31_32_div(
+ dal_fixed31_32_sub(
+ dal_fixed31_32_mul(m[3], m[7]),
+ dal_fixed31_32_mul(m[4], m[6])),
+ determinant);
+
+ im[7] = dal_fixed31_32_div(
+ dal_fixed31_32_mul(
+ dal_fixed31_32_sub(
+ dal_fixed31_32_mul(m[0], m[7]),
+ dal_fixed31_32_mul(m[1], m[6])),
+ neg),
+ determinant);
+
+ im[8] = dal_fixed31_32_div(
+ dal_fixed31_32_sub(
+ dal_fixed31_32_mul(m[0], m[4]),
+ dal_fixed31_32_mul(m[1], m[3])),
+ determinant);
+
+ return true;
+}
+
+void dal_gamut_space_multiply_matrices(
+ struct fixed31_32 *result,
+ struct fixed31_32 *m1,
+ struct fixed31_32 *m2,
+ uint32_t rows,
+ uint32_t cols1,
+ uint32_t cols2)
+{
+ uint32_t i, j, k;
+
+ for (i = 0 ; i < rows ; i++) {
+ for (j = 0 ; j < cols2 ; j++) {
+ result[(i * cols2) + j].value = 0;
+ for (k = 0 ; k < cols1 ; k++)
+ result[(i * cols2) + j] =
+ dal_fixed31_32_add(
+ result[(i * cols2) + j],
+ dal_fixed31_32_mul(
+ m1[(i * cols1) + k],
+ m2[(k * cols2) + j]));
+
+ }
+ }
+}
+
+bool dal_gamut_space_calculate_xyz_to_rgb_M3x3(
+ struct fixed31_32 *xyz_of_rgb,
+ struct fixed31_32 *xyz_of_white,
+ struct fixed31_32 *xyz_to_rgb)
+{
+ struct fixed31_32 m_inversed[9];
+ struct fixed31_32 s_vector[3];
+
+ if (!dal_gamut_space_compute_inverse_matrix_3x3(
+ xyz_of_rgb, m_inversed))
+ return false;
+
+ dal_gamut_space_multiply_matrices(
+ s_vector,
+ m_inversed,
+ xyz_of_white,
+ 3,
+ 3,
+ 1);
+
+ xyz_to_rgb[0] = dal_fixed31_32_mul(
+ xyz_of_rgb[0], s_vector[0]);
+ xyz_to_rgb[1] = dal_fixed31_32_mul(
+ xyz_of_rgb[1], s_vector[1]);
+ xyz_to_rgb[2] = dal_fixed31_32_mul(
+ xyz_of_rgb[2], s_vector[2]);
+ xyz_to_rgb[3] = dal_fixed31_32_mul(
+ xyz_of_rgb[3], s_vector[0]);
+ xyz_to_rgb[4] = dal_fixed31_32_mul(
+ xyz_of_rgb[4], s_vector[1]);
+ xyz_to_rgb[5] = dal_fixed31_32_mul(
+ xyz_of_rgb[5], s_vector[2]);
+ xyz_to_rgb[6] = dal_fixed31_32_mul(
+ xyz_of_rgb[6], s_vector[0]);
+ xyz_to_rgb[7] = dal_fixed31_32_mul(
+ xyz_of_rgb[7], s_vector[1]);
+ xyz_to_rgb[8] = dal_fixed31_32_mul(
+ xyz_of_rgb[8], s_vector[2]);
+
+ return true;
+}
+
+bool dal_gamut_space_allocate_calculation_matrix(
+ struct gamut_calculation_matrix *matrix)
+{
+ uint32_t size_of_allocation;
+
+ size_of_allocation = sizeof(struct fixed31_32) * 9 * 6 +
+ sizeof(struct fixed31_32) * 3;
+
+ matrix->transposed = dal_alloc(size_of_allocation);
+ if (!matrix->transposed)
+ return false;
+
+ matrix->xyz_to_rgb_custom = matrix->transposed + 9;
+ matrix->xyz_to_rgb_ref = matrix->xyz_to_rgb_custom + 9;
+ matrix->rgb_to_xyz_final = matrix->xyz_to_rgb_ref + 9;
+ matrix->result = matrix->rgb_to_xyz_final + 9;
+ matrix->xyz_of_white_ref = matrix->result + 9;
+ matrix->xyz_of_rgb_ref = matrix->xyz_of_white_ref + 3;
+
+ return true;
+}
+
+void dal_gamut_space_deallocate_calculation_matrix(
+ struct gamut_calculation_matrix *matrix)
+{
+ if (matrix->transposed != NULL) {
+ dal_free(matrix->transposed);
+ matrix->transposed = NULL;
+ }
+}
+
+void dal_gamut_space_transpose_matrix(
+ struct fixed31_32 *m,
+ uint32_t rows,
+ uint32_t cols,
+ struct fixed31_32 *transposed)
+{
+ uint32_t i, j;
+
+ for (i = 0 ; i < rows ; i++) {
+ for (j = 0 ; j < cols ; j++)
+ transposed[(j * rows) + i] =
+ m[(i * cols) + j];
+ }
+}
+
+
+bool dal_gamut_space_setup_white_point(
+ struct gamut_data *gamut,
+ struct ds_white_point_coordinates *data)
+{
+ struct color_space_coodinates csc;
+
+ if (gamut->option.bits.CUSTOM_WHITE_POINT == 1) {
+ data->white_x = gamut->white_point.custom.white_x;
+ data->white_y = gamut->white_point.custom.white_y;
+ return true;
+ }
+
+ if (dal_gamut_space_find_predefined_white_point(
+ gamut->white_point.predefined,
+ &csc)) {
+ data->white_x = csc.white_x;
+ data->white_y = csc.white_y;
+ return true;
+ }
+
+ return false;
+}
+
+bool dal_gamut_space_find_predefined_white_point(
+ union ds_gamut_white_point predefined,
+ struct color_space_coodinates *csc)
+{
+ bool ret = false;
+ const struct white_point_coodinates_entry *p;
+ uint32_t const_size;
+
+ const_size = ARRAY_SIZE(white_point_array);
+ for (p = white_point_array;
+ p < &white_point_array[const_size]; p++) {
+ if (p->index == predefined.u32all) {
+ csc->white_x = p->white_x;
+ csc->white_y = p->white_y;
+ ret = true;
+ break;
+ }
+ }
+ return ret;
+}
+
+
+bool dal_gamut_space_get_supported_gamuts(struct ds_gamut_info *data)
+{
+ data->gamut_space.bits.GAMUT_SPACE_CCIR709 = 1;
+ data->gamut_space.bits.GAMUT_SPACE_CCIR601 = 1;
+ data->gamut_space.bits.GAMUT_SPACE_ADOBERGB = 1;
+ data->gamut_space.bits.GAMUT_SPACE_CIERGB = 1;
+ data->gamut_space.bits.GAMUT_SPACE_CUSTOM = 1;
+
+ data->white_point.bits.GAMUT_WHITE_POINT_5000 = 1;
+ data->white_point.bits.GAMUT_WHITE_POINT_6500 = 1;
+ data->white_point.bits.GAMUT_WHITE_POINT_7500 = 1;
+ data->white_point.bits.GAMUT_WHITE_POINT_9300 = 1;
+ data->white_point.bits.GAMUT_WHITE_POINT_CUSTOM = 1;
+ return true;
+}
+
+static struct fixed31_32 power_to_fractional(uint8_t two_bytes)
+{
+ uint32_t i;
+ struct fixed31_32 data;
+ struct fixed31_32 pow;
+
+ data.value = 0;
+ pow = dal_fixed31_32_pow(
+ dal_fixed31_32_from_int(
+ (int64_t)EXP_NUMBER_1),
+ dal_fixed31_32_from_int(
+ (int64_t)EXP_NUMBER_2));
+
+ for (i = 0; i < 10 ; i++, two_bytes >>= 1) {
+ if (two_bytes & 0x0001)
+ data = dal_fixed31_32_add(
+ data, pow);
+ pow = dal_fixed31_32_mul_int(
+ pow, 2);
+ }
+ return data;
+}
+
+bool dal_gamut_space_convert_edid_format_color_charact(
+ const uint8_t pa[10],
+ struct color_characteristic *color_charact)
+{
+ uint8_t temp;
+
+ /* The chromaticity and white point values are expressed as fractional
+ * numbers accurate to the thousandth place.Each number is represented
+ * by a binary fraction which is 10 bits in length. In this fraction
+ * a value of one for the bit immediately right of the decimal point
+ * (bit 9) represents 2 raised to the -1 power. A value to 1 in the
+ * right most bit (bit 0) represents a value of 2 raised to the -10
+ * power.The high order bits (9 ~ 2) are stored as a single byte.
+ * The low order bits (1 ~ 0) are paired with other low order bits
+ to form a byte.*/
+
+ temp = (pa[2] << SHIFT_2) | ((pa[0] & MASK_C0) >> SHIFT_6);
+ color_charact->red_x = power_to_fractional(temp);
+
+ temp = (pa[3] << SHIFT_2) | ((pa[0] & MASK_30) >> SHIFT_4);
+ color_charact->red_y = power_to_fractional(temp);
+ if (dal_fixed31_32_eq(color_charact->red_y, dal_fixed31_32_zero))
+ return false;
+
+ temp = (pa[4] << SHIFT_2) | ((pa[0] & MASK_C) >> SHIFT_2);
+ color_charact->green_x = power_to_fractional(temp);
+
+ temp = (pa[5] << SHIFT_2) | ((pa[0] & MASK_3));
+ color_charact->green_y = power_to_fractional(temp);
+ if (dal_fixed31_32_eq(color_charact->green_y, dal_fixed31_32_zero))
+ return false;
+
+ temp = (pa[6] << SHIFT_2) | ((pa[1] & MASK_C0) >> SHIFT_6);
+ color_charact->blue_x = power_to_fractional(temp);
+
+ temp = (pa[7] << SHIFT_2) | ((pa[1] & MASK_30) >> SHIFT_4);
+ color_charact->blue_y = power_to_fractional(temp);
+ if (dal_fixed31_32_eq(color_charact->blue_y, dal_fixed31_32_zero))
+ return false;
+
+ temp = (pa[8] << SHIFT_2) | ((pa[1] & MASK_C) >> SHIFT_2);
+ color_charact->white_x = power_to_fractional(temp);
+
+ temp = (pa[9] << SHIFT_2) | ((pa[1] & MASK_3));
+ color_charact->white_y = power_to_fractional(temp);
+ if (dal_fixed31_32_eq(color_charact->white_y, dal_fixed31_32_zero))
+ return false;
+
+ return true;
+}
+
+bool dal_gamut_space_setup_predefined_regamma_coefficients(
+ struct gamut_data *data,
+ struct ds_regamma_lut *regamma)
+{
+ bool ret = false;
+
+ if (data->option.bits.CUSTOM_GAMUT_SPACE == 0) {
+ regamma->flags.u32all = 0;
+ ret = dal_gamut_space_find_predefined_gamut(
+ data->gamut.predefined,
+ NULL,
+ &regamma->coeff);
+
+ regamma->flags.bits.COEFF_FROM_USER = 1;
+ regamma->flags.bits.GAMMA_FROM_USER = 1;
+ }
+ return ret;
+}
diff --git a/drivers/gpu/drm/amd/dal/display_service/gamut_space.h b/drivers/gpu/drm/amd/dal/display_service/gamut_space.h
new file mode 100644
index 000000000000..cd238ec0b882
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/gamut_space.h
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2015 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_GAMUT_SPACE_H__
+#define __DAL_GAMUT_SPACE_H__
+
+#include "include/adjustment_types.h"
+#include "include/fixed32_32.h"
+
+#define EDID_GAMUT_COORDINATES 10
+#define GAMUT_MATRIX_SIZE_3X3 9
+#define EXP_NUMBER_1 2
+#define EXP_NUMBER_2 -10
+#define MASK_C0 0xC0
+#define MASK_30 0x30
+#define MASK_C 0x0C
+#define MASK_3 0x03
+#define SHIFT_2 2
+#define SHIFT_4 4
+#define SHIFT_6 6
+
+struct gamut_color_characteristics {
+ uint32_t gamma;
+ uint8_t color_charact[EDID_GAMUT_COORDINATES];
+};
+
+enum gamut_space_source {
+ GAMUT_SPACE_SOURCE_DEFAULT,
+ GAMUT_SPACE_SOURCE_USER_GAMUT,
+ GAMUT_SPACE_SOURCE_EDID
+};
+
+struct gamut_parameter {
+ enum gamut_space_source source;
+ struct gamut_data gamut_src;
+ struct ds_regamma_lut regamma;
+ union {
+ struct gamut_data gamut_dst;
+ struct gamut_color_characteristics color_charact;
+ };
+};
+
+struct gamut_space_entry {
+ uint32_t index;
+ uint32_t red_x;
+ uint32_t red_y;
+ uint32_t green_x;
+ uint32_t green_y;
+ uint32_t blue_x;
+ uint32_t blue_y;
+
+ int32_t a0;
+ int32_t a1;
+ int32_t a2;
+ int32_t a3;
+ int32_t gamma;
+};
+
+struct white_point_coodinates_entry {
+ uint32_t index;
+ uint32_t white_x;
+ uint32_t white_y;
+};
+union update_color_flags {
+ uint32_t raw;
+ struct {
+ uint32_t REGAMMA:1;
+ uint32_t GAMUT_DST:1;
+ uint32_t GAMUT_SRC:1;
+ uint32_t RESERVED:29;
+ } bits;
+};
+
+struct color_characteristic {
+ struct fixed31_32 red_x;
+ struct fixed31_32 red_y;
+ struct fixed31_32 green_x;
+ struct fixed31_32 green_y;
+ struct fixed31_32 blue_x;
+ struct fixed31_32 blue_y;
+ struct fixed31_32 white_x;
+ struct fixed31_32 white_y;
+};
+
+struct color_space_coodinates {
+ uint32_t red_x;
+ uint32_t red_y;
+ uint32_t green_x;
+ uint32_t green_y;
+ uint32_t blue_x;
+ uint32_t blue_y;
+ uint32_t white_x;
+ uint32_t white_y;
+};
+
+struct gamut_matrixs {
+ struct fixed31_32 *rgb_coeff_dst;
+ struct fixed31_32 *white_coeff_dst;
+ struct fixed31_32 *rgb_coeff_src;
+ struct fixed31_32 *white_coeff_src;
+};
+
+struct gamut_calculation_matrix {
+ struct fixed31_32 *transposed;
+ struct fixed31_32 *xyz_to_rgb_custom;
+ struct fixed31_32 *xyz_to_rgb_ref;
+ struct fixed31_32 *rgb_to_xyz_final;
+ struct fixed31_32 *result;
+ struct fixed31_32 *xyz_of_white_ref;
+ struct fixed31_32 *xyz_of_rgb_ref;
+};
+
+void dal_gamut_space_reset_gamut(
+ struct gamut_data *data,
+ bool gamut,
+ bool white_point);
+
+bool dal_gamut_space_update_gamut(
+ struct gamut_parameter *gamut,
+ bool set_regamma,
+ union update_color_flags *flags);
+
+bool dal_gamut_space_setup_default_gamut(
+ enum adjustment_id adj_id,
+ struct gamut_data *data,
+ bool gamut,
+ bool white_point);
+
+bool dal_gamut_space_build_gamut_space_matrix(
+ struct gamut_parameter *gamut,
+ uint32_t temp_matrix[GAMUT_MATRIX_SIZE_3X3],
+ struct ds_regamma_lut *regamma,
+ union update_color_flags *flags);
+
+bool dal_gamut_space_setup_white_point(
+ struct gamut_data *gamut,
+ struct ds_white_point_coordinates *data);
+
+bool dal_gamut_space_get_supported_gamuts(
+ struct ds_gamut_info *data);
+
+bool dal_gamut_space_convert_edid_format_color_charact(
+ const uint8_t pa[10],
+ struct color_characteristic *color_charact);
+
+bool dal_gamut_space_find_predefined_gamut(
+ union ds_gamut_spaces predefine,
+ struct color_space_coodinates *csc,
+ struct ds_regamma_coefficients_ex *gamma_coeff);
+
+bool dal_gamut_space_find_regamma_coefficients(
+ struct ds_regamma_coefficients_ex *coeff,
+ union ds_gamut_spaces *predefine);
+
+bool dal_gamut_space_find_color_coordinates(
+ struct color_space_coodinates *csc,
+ union ds_gamut_spaces *predefine);
+
+bool dal_gamut_space_is_equal_gamma_coefficients(
+ struct ds_regamma_coefficients_ex *coeff,
+ struct ds_regamma_coefficients_ex *coeff_custom,
+ union update_color_flags *flags);
+
+bool dal_gamut_space_find_predefined_white_point(
+ union ds_gamut_white_point predefined,
+ struct color_space_coodinates *csc);
+
+bool dal_gamut_space_build_default_unity_matrix(
+ uint32_t temp_matrix[GAMUT_MATRIX_SIZE_3X3],
+ struct ds_regamma_lut *regamma);
+
+bool dal_gamut_space_allocate_matrix(
+ struct gamut_matrixs *matrix);
+
+void dal_gamut_space_dellocate_matrix(
+ struct gamut_matrixs *matrix);
+
+bool dal_gamut_space_build_gamut_matrix(
+ struct fixed31_32 *rgb,
+ struct fixed31_32 *white,
+ struct ds_regamma_lut *regamma,
+ union update_color_flags *flags,
+ struct ds_regamma_lut *custom_regamma,
+ struct gamut_data *data,
+ bool is_source);
+
+bool dal_gamut_build_edid_matrix(
+ struct ds_regamma_lut *regamma,
+ union update_color_flags *flags,
+ uint32_t edid_gamma,
+ struct fixed31_32 *rgb,
+ struct fixed31_32 *white,
+ uint8_t pa[EDID_GAMUT_COORDINATES]);
+
+bool dal_gamut_space_build_chromaticity_matrix(
+ struct fixed31_32 *rgb,
+ struct fixed31_32 *white,
+ struct color_characteristic *pm);
+
+bool dal_gamut_space_gamut_to_color_matrix(
+ struct fixed31_32 *xyz_of_rgb,
+ struct fixed31_32 *xyz_of_white,
+ struct fixed31_32 *ref_xyz_of_rgb,
+ struct fixed31_32 *ref_xyz_of_white,
+ bool invert,
+ uint32_t temp_matrix[GAMUT_MATRIX_SIZE_3X3]);
+
+struct fixed31_32 dal_gamut_space_find_3x3_det(
+ struct fixed31_32 *m);
+
+bool dal_gamut_space_compute_inverse_matrix_3x3(
+ struct fixed31_32 *m,
+ struct fixed31_32 *im);
+
+void dal_gamut_space_multiply_matrices(
+ struct fixed31_32 *result,
+ struct fixed31_32 *m1,
+ struct fixed31_32 *m2,
+ uint32_t rows,
+ uint32_t cols1,
+ uint32_t cols2);
+
+bool dal_gamut_space_calculate_xyz_to_rgb_M3x3(
+ struct fixed31_32 *xyz_of_rgb,
+ struct fixed31_32 *xyz_of_white,
+ struct fixed31_32 *xyz_to_rgb);
+
+bool dal_gamut_space_allocate_calculation_matrix(
+ struct gamut_calculation_matrix *matrix);
+
+void dal_gamut_space_deallocate_calculation_matrix(
+ struct gamut_calculation_matrix *matrix);
+
+void dal_gamut_space_transpose_matrix(
+ struct fixed31_32 *m,
+ uint32_t rows,
+ uint32_t cols,
+ struct fixed31_32 *transposed);
+
+bool dal_gamut_space_convert_edid_format_color_charact(
+ const uint8_t pa[10],
+ struct color_characteristic *color_charact);
+
+bool dal_gamut_space_setup_predefined_regamma_coefficients(
+ struct gamut_data *data,
+ struct ds_regamma_lut *regamma);
+
+#endif /* __DAL_GAMUT_SPACE_H__ */
diff --git a/drivers/gpu/drm/amd/dal/display_service/grph_colors_group.c b/drivers/gpu/drm/amd/dal/display_service/grph_colors_group.c
new file mode 100644
index 000000000000..e70624188285
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/grph_colors_group.c
@@ -0,0 +1,1326 @@
+/*
+ * Copyright 2015 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/hw_sequencer_types.h"
+#include "include/display_service_types.h"
+#include "include/display_path_interface.h"
+#include "include/set_mode_interface.h"
+#include "include/adjustment_interface.h"
+#include "include/hw_sequencer_interface.h"
+#include "include/hw_adjustment_set.h"
+#include "include/logger_interface.h"
+#include "include/fixed31_32.h"
+
+#include "ds_dispatch.h"
+#include "adjustment_container.h"
+#include "grph_colors_group.h"
+#include "gamut_space.h"
+#include "color_temperature.h"
+#include "ds_translation.h"
+
+enum ds_color_space dal_grph_colors_group_get_color_space(
+ struct grph_colors_group *grph_colors_adj,
+ const struct crtc_timing *timing,
+ const struct display_path *disp_path,
+ struct adj_container *adj_container)
+{
+ const struct adjustment_info *nominal_limited = NULL;
+ enum ds_color_space color_space = DS_COLOR_SPACE_UNKNOWN;
+
+ if (disp_path == NULL || timing == NULL)
+ return color_space;
+
+ if (adj_container != NULL) {
+ nominal_limited = dal_adj_info_set_get_adj_info(
+ &adj_container->adj_info_set,
+ ADJ_ID_NOMINAL_RANGE_RGB_LIMITED);
+ switch (dal_display_path_get_query_signal(
+ disp_path, SINK_LINK_INDEX)) {
+ case SIGNAL_TYPE_MVPU_A:
+ case SIGNAL_TYPE_MVPU_B:
+ case SIGNAL_TYPE_MVPU_AB:
+ color_space = dal_adj_container_get_color_space(
+ adj_container);
+ break;
+ default:
+ break;
+ }
+ }
+ if (color_space == DS_COLOR_SPACE_UNKNOWN) {
+ enum ds_color_space hdmi_request_color_space =
+ DS_COLOR_SPACE_SRGB_LIMITEDRANGE;
+ if (nominal_limited != NULL &&
+ (nominal_limited->adj_data.ranged.cur ==
+ nominal_limited->adj_data.ranged.min))
+ hdmi_request_color_space =
+ DS_COLOR_SPACE_SRGB_FULLRANGE;
+ color_space =
+ dal_grph_colors_group_build_default_color_space(
+ grph_colors_adj,
+ timing,
+ disp_path,
+ hdmi_request_color_space);
+ if (nominal_limited != NULL &&
+ nominal_limited->adj_data.ranged.cur !=
+ nominal_limited->adj_data.ranged.min &&
+ color_space == DS_COLOR_SPACE_SRGB_FULLRANGE)
+ color_space = DS_COLOR_SPACE_SRGB_LIMITEDRANGE;
+ else if (nominal_limited != NULL &&
+ nominal_limited->adj_data.ranged.cur ==
+ nominal_limited->adj_data.ranged.min &&
+ color_space == DS_COLOR_SPACE_SRGB_LIMITEDRANGE)
+ color_space = DS_COLOR_SPACE_SRGB_FULLRANGE;
+
+ }
+ return color_space;
+}
+
+enum ds_return dal_grph_colors_group_set_adjustment(
+ struct grph_colors_group *grph_colors_adj,
+ struct display_path *disp_path,
+ enum adjustment_id adj_id,
+ uint32_t value)
+{
+ enum ds_return ret = DS_ERROR;
+ const struct path_mode_set_with_data *pms_wd;
+ struct adj_container *adj_container;
+ const struct path_mode *path_mode;
+ const struct adjustment_info *adj_info;
+ struct gamut_parameter *gamut = NULL;
+ struct ds_regamma_lut *regamma = NULL;
+ struct hw_adjustment_color_control *color_control = NULL;
+ uint32_t display_index;
+
+ if (!disp_path)
+ return DS_ERROR;
+
+ display_index = dal_display_path_get_display_index(
+ disp_path);
+
+ pms_wd = dal_ds_dispatch_get_active_pms_with_data(
+ grph_colors_adj->ds);
+ if (!pms_wd)
+ return DS_ERROR;
+
+ adj_container = dal_ds_dispatch_get_adj_container_for_path(
+ grph_colors_adj->ds,
+ display_index);
+
+ if (!adj_container)
+ return DS_ERROR;
+
+ path_mode =
+ dal_pms_with_data_get_path_mode_for_display_index(
+ pms_wd,
+ display_index);
+
+ if (!path_mode)
+ return DS_ERROR;
+
+
+ adj_info = dal_adj_info_set_get_adj_info(
+ &adj_container->adj_info_set,
+ adj_id);
+
+ if (!adj_info)
+ return DS_ERROR;
+
+ if (dal_adj_container_is_adjustment_committed(
+ adj_container, adj_id) &&
+ (adj_info->adj_data.ranged.cur == value))
+ return DS_SUCCESS;
+
+ if (!dal_adj_info_set_update_cur_value(
+ &adj_container->adj_info_set,
+ adj_id, value))
+ return DS_ERROR;
+
+ gamut = dal_alloc(sizeof(*gamut));
+ if (!gamut)
+ goto gamut_fail;
+ regamma = dal_alloc(sizeof(*regamma));
+ if (!regamma)
+ goto regamma_fail;
+ color_control = dal_alloc(sizeof(*color_control));
+ if (!color_control)
+ goto color_control_fail;
+
+ if (dal_grph_colors_group_compute_hw_adj_color_control(
+ grph_colors_adj,
+ adj_container,
+ &path_mode->mode_timing->crtc_timing,
+ disp_path,
+ adj_id,
+ gamut,
+ regamma,
+ color_control)) {
+ enum ds_color_space color_space;
+
+ color_control->surface_pixel_format =
+ path_mode->pixel_format;
+
+ dal_adj_container_set_regamma(
+ adj_container,
+ regamma);
+
+ dal_hw_sequencer_set_color_control_adjustment(
+ grph_colors_adj->hws,
+ dal_display_path_get_controller(disp_path),
+ color_control);
+
+ color_space =
+ dal_ds_translation_color_space_from_hw_color_space(
+ color_control->color_space);
+
+ dal_adj_container_update_color_space(
+ adj_container,
+ color_space);
+ dal_adj_container_commit_adj(adj_container, adj_id);
+ ret = DS_SUCCESS;
+ }
+
+ dal_free(color_control);
+color_control_fail:
+ dal_free(regamma);
+regamma_fail:
+ dal_free(gamut);
+gamut_fail:
+ return ret;
+}
+
+static int32_t get_hw_value_from_sw_value(
+ const struct hw_adjustment_range *hw_range,
+ const struct adjustment_info *sw_range)
+{
+ int32_t sw_val = sw_range->adj_data.ranged.cur;
+ int32_t sw_min = sw_range->adj_data.ranged.min;
+ int32_t sw_max = sw_range->adj_data.ranged.max;
+ int32_t hw_max = hw_range->max;
+ int32_t hw_min = hw_range->min;
+ int32_t sw_data = sw_max - sw_min;
+ int32_t hw_data = hw_max - hw_min;
+ int32_t hw_val;
+
+ if (sw_data == 0)
+ return hw_min;
+ if (sw_data != hw_data)
+ hw_val =
+ (sw_val - sw_min) * hw_data / sw_data + hw_min;
+ else {
+ hw_val = sw_val;
+ if (sw_min != hw_min)
+ hw_val += (hw_min - sw_min);
+ }
+
+ return hw_val;
+}
+
+static bool is_current_same_as_default(
+ struct adjustment_info *adj_info)
+{
+ return adj_info->adj_data.ranged.cur ==
+ adj_info->adj_data.ranged.def;
+}
+
+bool dal_grph_colors_group_compute_hw_adj_color_control(
+ struct grph_colors_group *grph_colors_adj,
+ struct adj_container *adj_container,
+ const struct crtc_timing *timing,
+ struct display_path *disp_path,
+ enum adjustment_id reason_id,
+ struct gamut_parameter *gamut,
+ struct ds_regamma_lut *regamma,
+ struct hw_adjustment_color_control *color_control)
+{
+ struct adjustment_info *brightness =
+ dal_adj_info_set_get_adj_info(
+ &adj_container->adj_info_set,
+ ADJ_ID_BRIGHTNESS);
+ struct adjustment_info *contrast =
+ dal_adj_info_set_get_adj_info(
+ &adj_container->adj_info_set,
+ ADJ_ID_CONTRAST);
+ struct adjustment_info *hue =
+ dal_adj_info_set_get_adj_info(
+ &adj_container->adj_info_set,
+ ADJ_ID_HUE);
+ struct adjustment_info *saturation =
+ dal_adj_info_set_get_adj_info(
+ &adj_container->adj_info_set,
+ ADJ_ID_SATURATION);
+ struct adjustment_info *temperature =
+ dal_adj_info_set_get_adj_info(
+ &adj_container->adj_info_set,
+ ADJ_ID_TEMPERATURE);
+ struct adjustment_info *temperature_src =
+ dal_adj_info_set_get_adj_info(
+ &adj_container->adj_info_set,
+ ADJ_ID_TEMPERATURE_SOURCE);
+ const struct display_characteristics *disp_char =
+ dal_adj_container_get_disp_character(
+ adj_container);
+ struct hw_color_control_range hw_color_range;
+ struct white_point_data white_point;
+ const struct ds_regamma_lut *const_regamma = NULL;
+ int32_t requested_temperature;
+ bool gamut_adj_avails;
+ enum signal_type signal;
+
+ /* reset updated info */
+ grph_colors_adj->regamma_updated = false;
+ grph_colors_adj->gamut_dst_updated = false;
+ grph_colors_adj->gamut_src_updated = false;
+
+ if (NULL == grph_colors_adj->hws ||
+ NULL == brightness ||
+ NULL == contrast ||
+ NULL == hue ||
+ NULL == saturation ||
+ NULL == temperature ||
+ NULL == disp_path)
+ return false;
+
+ dal_memset(&hw_color_range, 0, sizeof(hw_color_range));
+ dal_memset(&white_point, 0, sizeof(white_point));
+ requested_temperature = temperature->adj_data.ranged.cur;
+ signal = dal_display_path_get_query_signal(
+ disp_path, SINK_LINK_INDEX);
+ color_control->adjust_divider = ADJUST_DIVIDER;
+ color_control->temperature_divider = GAMUT_DIVIDER;
+ gamut_adj_avails =
+ dal_hw_sequencer_is_support_custom_gamut_adj(
+ grph_colors_adj->hws,
+ disp_path,
+ HW_GRAPHIC_SURFACE);
+
+ if (!dal_adj_container_get_gamut(
+ adj_container,
+ ADJ_ID_GAMUT_SOURCE_GRPH,
+ &gamut->gamut_src))
+ return false;
+
+ if (!dal_adj_container_get_gamut(
+ adj_container,
+ ADJ_ID_GAMUT_DESTINATION,
+ &gamut->gamut_dst))
+ return false;
+
+ const_regamma = dal_adj_container_get_regamma(
+ adj_container);
+ if (!const_regamma)
+ return false;
+ dal_memmove(&gamut->regamma, const_regamma, sizeof(gamut->regamma));
+
+ if (signal == SIGNAL_TYPE_HDMI_TYPE_A)
+ gamut->source = GAMUT_SPACE_SOURCE_DEFAULT;
+ else {
+ gamut->source =
+ temperature_src->adj_data.ranged.cur ==
+ COLOR_TEMPERATURE_SOURCE_EDID ?
+ GAMUT_SPACE_SOURCE_EDID :
+ GAMUT_SPACE_SOURCE_USER_GAMUT;
+ if (requested_temperature == -1)
+ gamut->source = GAMUT_SPACE_SOURCE_EDID;
+
+ if (disp_char == NULL && gamut->source ==
+ GAMUT_SPACE_SOURCE_EDID)
+ gamut->source = GAMUT_SPACE_SOURCE_DEFAULT;
+
+ if (gamut->source == GAMUT_SPACE_SOURCE_EDID) {
+ uint32_t i;
+
+ dal_gamut_space_reset_gamut(
+ &gamut->gamut_dst, true, true);
+
+ for (i = 0;
+ i < sizeof(gamut->color_charact.color_charact);
+ i++) {
+ gamut->color_charact.color_charact[i] =
+ disp_char->color_characteristics[i];
+ }
+ if (disp_char->gamma > 0)
+ gamut->color_charact.gamma =
+ (disp_char->gamma + 100)*10;
+ else
+ gamut->color_charact.gamma = 0;
+ }
+ }
+ if (gamut->source == GAMUT_SPACE_SOURCE_DEFAULT) {
+ requested_temperature = temperature->adj_data.ranged.def;
+ if (!dal_color_temperature_find_white_point(
+ requested_temperature,
+ &white_point))
+ return false;
+ dal_gamut_space_reset_gamut(
+ &gamut->gamut_src, false, true);
+ gamut->gamut_src.option.bits.CUSTOM_WHITE_POINT = 1;
+ gamut->gamut_src.white_point.custom.white_x =
+ white_point.white_x;
+ gamut->gamut_src.white_point.custom.white_y =
+ white_point.white_y;
+
+ if (!dal_adj_container_validate_gamut(
+ adj_container,
+ &gamut->gamut_src))
+ return false;
+
+ dal_adj_container_update_gamut(
+ adj_container,
+ ADJ_ID_GAMUT_SOURCE_GRPH,
+ &gamut->gamut_src);
+ {
+ struct adjustment_info *non_const_temp = temperature;
+
+ non_const_temp->adj_data.ranged.cur =
+ requested_temperature;
+ }
+ }
+ {
+ union update_color_flags flags = {0};
+
+ if (!dal_gamut_space_update_gamut(
+ gamut, false, &flags))
+ return false;
+ if (flags.bits.GAMUT_DST == 1)
+ dal_adj_container_update_gamut(
+ adj_container,
+ ADJ_ID_GAMUT_DESTINATION,
+ &gamut->gamut_dst);
+ if (reason_id != ADJ_ID_GAMUT_SOURCE_GRPH &&
+ reason_id != ADJ_ID_GAMUT_DESTINATION) {
+ if (gamut->source == GAMUT_SPACE_SOURCE_EDID)
+ dal_gamut_space_setup_default_gamut(
+ reason_id,
+ &gamut->gamut_src,
+ false,
+ true);
+ }
+ if (!dal_gamut_space_build_gamut_space_matrix(
+ gamut,
+ color_control->temperature_matrix,
+ regamma,
+ &flags))
+ return false;
+
+ if (flags.bits.REGAMMA > 0)
+ grph_colors_adj->regamma_updated = true;
+ if (flags.bits.GAMUT_SRC > 0)
+ grph_colors_adj->gamut_src_updated = true;
+ if (flags.bits.GAMUT_DST > 0)
+ grph_colors_adj->gamut_dst_updated = true;
+ }
+ if (dal_hw_sequencer_get_hw_color_adj_range(
+ grph_colors_adj->hws,
+ disp_path,
+ &hw_color_range) != HWSS_RESULT_OK)
+ return false;
+ color_control->color_space =
+ dal_ds_translation_hw_color_space_from_color_space(
+ dal_grph_colors_group_get_color_space(
+ grph_colors_adj,
+ timing,
+ disp_path,
+ adj_container));
+ if (color_control->color_space ==
+ HW_COLOR_SPACE_UNKNOWN)
+ return false;
+ {
+ struct hw_crtc_timing hw_timing;
+ enum signal_type asic_signal =
+ dal_display_path_get_query_signal(
+ disp_path, ASIC_LINK_INDEX);
+ dal_ds_translation_hw_crtc_timing_from_crtc_timing(
+ &hw_timing,
+ timing,
+ VIEW_3D_FORMAT_NONE,
+ asic_signal);
+
+ color_control->color_depth =
+ hw_timing.flags.COLOR_DEPTH;
+ color_control->brightness =
+ get_hw_value_from_sw_value(
+ &hw_color_range.brightness,
+ brightness);
+ color_control->contrast =
+ get_hw_value_from_sw_value(
+ &hw_color_range.contrast,
+ contrast);
+ color_control->hue =
+ get_hw_value_from_sw_value(
+ &hw_color_range.hue,
+ hue);
+ color_control->saturation =
+ get_hw_value_from_sw_value(
+ &hw_color_range.saturation,
+ saturation);
+ if (gamut->source == GAMUT_SPACE_SOURCE_USER_GAMUT &&
+ gamut_adj_avails == false &&
+ is_current_same_as_default(saturation) &&
+ is_current_same_as_default(contrast) &&
+ is_current_same_as_default(brightness) &&
+ is_current_same_as_default(hue) &&
+ is_current_same_as_default(temperature))
+ color_control->option = HWS_COLOR_MATRIX_HW_DEFAULT;
+ else
+ color_control->option = HWS_COLOR_MATRIX_SW;
+
+ }
+
+ return true;
+}
+
+bool dal_grph_colors_group_build_color_control_adj(
+ struct grph_colors_group *grph_colors_adj,
+ const struct path_mode *mode,
+ struct display_path *disp_path,
+ struct hw_adjustment_set *set)
+{
+ struct adj_container *adj_container;
+ struct gamut_parameter *gamut = NULL;
+ struct ds_regamma_lut *regamma = NULL;
+ struct hw_adjustment_color_control *color_control = NULL;
+ enum ds_color_space color_space;
+
+ if (!disp_path)
+ return false;
+ gamut = dal_alloc(sizeof(*gamut));
+ if (!gamut)
+ goto gamut_fail;
+ regamma = dal_alloc(sizeof(*regamma));
+ if (!regamma)
+ goto regamma_fail;
+ color_control = dal_alloc(sizeof(*color_control));
+ if (!color_control)
+ goto color_control_fail;
+
+ adj_container = dal_ds_dispatch_get_adj_container_for_path(
+ grph_colors_adj->ds,
+ mode->display_path_index);
+ if (!adj_container)
+ goto adj_container_fail;
+
+ color_control->color_space = HW_COLOR_SPACE_UNKNOWN;
+
+ if (!dal_grph_colors_group_compute_hw_adj_color_control(
+ grph_colors_adj,
+ adj_container,
+ &mode->mode_timing->crtc_timing,
+ disp_path,
+ ADJ_ID_INVALID,
+ gamut,
+ regamma,
+ color_control))
+ goto adj_container_fail;
+ color_control->surface_pixel_format = mode->pixel_format;
+ set->color_control = color_control;
+ color_space = dal_ds_translation_color_space_from_hw_color_space(
+ color_control->color_space);
+ dal_adj_container_update_color_space(
+ adj_container,
+ color_space);
+
+ dal_free(regamma);
+ dal_free(gamut);
+
+ return true;
+
+adj_container_fail:
+ dal_free(color_control);
+color_control_fail:
+ dal_free(regamma);
+regamma_fail:
+ dal_free(gamut);
+gamut_fail:
+ return false;
+}
+
+enum ds_color_space dal_grph_colors_group_build_default_color_space(
+ struct grph_colors_group *grph_colors_adj,
+ const struct crtc_timing *timing,
+ const struct display_path *disp_path,
+ enum ds_color_space hdmi_request_color_space)
+{
+ enum ds_color_space color_space =
+ DS_COLOR_SPACE_SRGB_FULLRANGE;
+
+ switch (dal_display_path_get_query_signal(
+ disp_path, SINK_LINK_INDEX)) {
+ case SIGNAL_TYPE_DISPLAY_PORT:
+ case SIGNAL_TYPE_DISPLAY_PORT_MST:
+ case SIGNAL_TYPE_EDP:
+ if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422 ||
+ timing->pixel_encoding == PIXEL_ENCODING_YCBCR444) {
+ color_space = (timing->pix_clk_khz > PIXEL_CLOCK) ?
+ DS_COLOR_SPACE_YCBCR709 :
+ DS_COLOR_SPACE_YCBCR601;
+ if (timing->flags.YONLY == 1)
+ color_space =
+ (timing->pix_clk_khz > PIXEL_CLOCK) ?
+ DS_COLOR_SPACE_YCBCR709_YONLY :
+ DS_COLOR_SPACE_YCBCR601_YONLY;
+ }
+ break;
+ case SIGNAL_TYPE_HDMI_TYPE_A:
+ {
+ uint32_t pix_clk_khz;
+
+ color_space = hdmi_request_color_space;
+ if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422 &&
+ timing->pixel_encoding == PIXEL_ENCODING_YCBCR444) {
+ if (timing->timing_standard ==
+ TIMING_STANDARD_CEA770 &&
+ timing->timing_standard ==
+ TIMING_STANDARD_CEA861)
+ color_space = DS_COLOR_SPACE_SRGB_FULLRANGE;
+ /* else {
+ union cea_video_capability_data_block
+ vcdb = {{0 }};
+ bool ret =
+ dal_edid_base_get_cea_video_capability_data_block(
+ disp_path->dcs->edid_mgr->edid_list,
+ &vcdb);
+ if ((ret == true) && (vcdb.bits.QS == 1))
+ color_space = DS_COLOR_SPACE_SRGB_FULLRANGE;
+ } */
+ pix_clk_khz = timing->pix_clk_khz / 10;
+ if (timing->h_addressable == 640 &&
+ timing->v_addressable == 480 &&
+ (pix_clk_khz == 2520 || pix_clk_khz == 2517))
+ color_space = DS_COLOR_SPACE_SRGB_FULLRANGE;
+ } else {
+ if (timing->timing_standard ==
+ TIMING_STANDARD_CEA770 ||
+ timing->timing_standard ==
+ TIMING_STANDARD_CEA861) {
+ /* struct cea_colorimetry_data_block
+ * data_block = {0};
+ if (dal_edid_base_get_cea_colorimetry_data_block(
+ disp_path->dcs->edid_mgr->edid_list,
+ &data_block)) {
+ if (data_block->flag.XV_YCC601 == 1 &&
+ data_block->flag.XV_YCC709 == 1)
+ color_space =
+ (timing->pix_clk_khz > PIXEL_CLOCK) ?
+ DS_COLOR_SPACE_YCBCR709 :
+ DS_COLOR_SPACE_YCBCR601;
+ else
+ color_space =
+ (data_block->flag.XV_YCC709 == 1) ?
+ DS_COLOR_SPACE_YCBCR709 :
+ DS_COLOR_SPACE_YCBCR601;
+ } else */
+ color_space =
+ (timing->pix_clk_khz > PIXEL_CLOCK) ?
+ DS_COLOR_SPACE_YCBCR709 :
+ DS_COLOR_SPACE_YCBCR601;
+ }
+ }
+ break;
+ }
+ default:
+ switch (timing->pixel_encoding) {
+ case PIXEL_ENCODING_YCBCR422:
+ case PIXEL_ENCODING_YCBCR444:
+ if (timing->pix_clk_khz > PIXEL_CLOCK)
+ color_space = DS_COLOR_SPACE_YCBCR709;
+ else
+ color_space = DS_COLOR_SPACE_YCBCR601;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ return color_space;
+}
+enum ds_color_space dal_grph_colors_group_adjust_color_space(
+ struct grph_colors_group *grph_colors_adj,
+ enum ds_color_space color_space,
+ bool rgb_limited)
+{
+ if (rgb_limited && color_space == DS_COLOR_SPACE_SRGB_FULLRANGE)
+ color_space = DS_COLOR_SPACE_SRGB_LIMITEDRANGE;
+ return color_space;
+}
+
+bool dal_grph_colors_group_synch_color_temperature_with_gamut(
+ struct grph_colors_group *grph_colors_adj,
+ struct adj_container *adj_container)
+{
+ struct gamut_data gamut_data;
+ struct ds_white_point_coordinates data;
+ struct white_point_data white_data;
+ int32_t temperature;
+ bool extra_match;
+
+ dal_memset(&gamut_data, 0, sizeof(gamut_data));
+ dal_memset(&data, 0, sizeof(data));
+ dal_memset(&white_data, 0, sizeof(white_data));
+
+ dal_adj_container_get_gamut(
+ adj_container,
+ ADJ_ID_GAMUT_SOURCE_GRPH,
+ &gamut_data);
+ if (!dal_gamut_space_setup_white_point(
+ &gamut_data,
+ &data))
+ return false;
+
+ white_data.white_x = data.white_x;
+ white_data.white_y = data.white_y;
+
+ if (!dal_color_temperature_find_color_temperature(
+ &white_data,
+ &temperature,
+ &extra_match))
+ return false;
+
+ if (!dal_adj_info_set_update_cur_value(
+ &adj_container->adj_info_set,
+ ADJ_ID_TEMPERATURE,
+ temperature))
+ return false;
+
+ return true;
+}
+
+bool dal_grph_colors_group_synch_gamut_with_color_temperature(
+ struct grph_colors_group *grph_colors_adj,
+ struct adj_container *adj_container)
+{
+ struct gamut_data gamut_data;
+ struct white_point_data white_data;
+ struct adjustment_info *temperature =
+ dal_adj_info_set_get_adj_info(
+ &adj_container->adj_info_set,
+ ADJ_ID_TEMPERATURE);
+
+ dal_memset(&gamut_data, 0, sizeof(gamut_data));
+ dal_memset(&white_data, 0, sizeof(white_data));
+
+ if (!dal_color_temperature_find_white_point(
+ temperature->adj_data.ranged.cur,
+ &white_data))
+ return false;
+ dal_adj_container_get_gamut(
+ adj_container,
+ ADJ_ID_GAMUT_SOURCE_GRPH,
+ &gamut_data);
+ dal_gamut_space_reset_gamut(
+ &gamut_data,
+ false,
+ true);
+
+ gamut_data.option.bits.CUSTOM_WHITE_POINT = 1;
+ gamut_data.white_point.custom.white_x = white_data.white_x;
+ gamut_data.white_point.custom.white_y = white_data.white_y;
+
+ if (!dal_adj_container_validate_gamut(
+ adj_container,
+ &gamut_data))
+ return false;
+
+ dal_adj_container_update_gamut(
+ adj_container,
+ ADJ_ID_GAMUT_SOURCE_GRPH,
+ &gamut_data);
+ return true;
+
+}
+
+bool dal_grph_colors_group_get_color_temperature(
+ struct grph_colors_group *grph_colors_adj,
+ struct adj_container *adj_container,
+ int32_t *temp)
+{
+ struct gamut_data gamut_data;
+ struct ds_white_point_coordinates data;
+ struct white_point_data white_data;
+ bool exact_match;
+
+ dal_adj_container_get_gamut(
+ adj_container,
+ ADJ_ID_GAMUT_SOURCE_GRPH,
+ &gamut_data);
+ if (dal_gamut_space_setup_white_point(
+ &gamut_data,
+ &data)) {
+ white_data.white_x = data.white_x;
+ white_data.white_y = data.white_y;
+ return dal_color_temperature_find_color_temperature(
+ &white_data, temp, &exact_match);
+ }
+ return false;
+}
+
+enum ds_return dal_grph_colors_group_set_color_graphics_gamut(
+ struct grph_colors_group *grph_colors_adj,
+ struct display_path *disp_path,
+ struct gamut_data *gamut_data,
+ enum adjustment_id adj_id,
+ bool apply_to_hw)
+{
+ uint32_t display_index;
+ struct adj_container *adj_container = NULL;
+ const struct path_mode_set_with_data *pms_wd = NULL;
+ const struct path_mode *path_mode = NULL;
+ struct hw_adjustment_color_control *color_control = NULL;
+ struct gamut_parameter *gamut = NULL;
+ struct ds_regamma_lut *regamma = NULL;
+ struct ds_regamma_lut *old_regamma = NULL;
+
+ if (!disp_path)
+ return DS_ERROR;
+ display_index = dal_display_path_get_display_index(
+ disp_path);
+
+ adj_container = dal_ds_dispatch_get_adj_container_for_path(
+ grph_colors_adj->ds, display_index);
+ if (!adj_container)
+ return DS_ERROR;
+
+ pms_wd = dal_ds_dispatch_get_active_pms_with_data(
+ grph_colors_adj->ds);
+ if (!pms_wd)
+ return DS_ERROR;
+
+ path_mode = dal_pms_with_data_get_path_mode_for_display_index(
+ pms_wd, display_index);
+ if (!path_mode)
+ return DS_ERROR;
+
+ if (!dal_hw_sequencer_is_support_custom_gamut_adj(
+ grph_colors_adj->hws,
+ disp_path,
+ HW_GRAPHIC_SURFACE))
+ return DS_ERROR;
+
+ if (!dal_adj_container_validate_gamut(
+ adj_container,
+ gamut_data))
+ return DS_ERROR;
+
+ dal_adj_container_update_gamut(
+ adj_container,
+ adj_id, gamut_data);
+
+ if (apply_to_hw) {
+ enum hwss_result result;
+ enum ds_color_space color_space;
+
+ color_control = dal_alloc(sizeof(*color_control));
+ if (!color_control)
+ return DS_ERROR;
+ gamut = dal_alloc(sizeof(*gamut));
+ if (!gamut)
+ goto gamut_fail;
+ regamma = dal_alloc(sizeof(*regamma));
+ if (!regamma)
+ goto regamma_fail;
+ old_regamma = dal_alloc(sizeof(*old_regamma));
+ if (!old_regamma)
+ goto old_regamma_fail;
+
+ if (!dal_grph_colors_group_compute_hw_adj_color_control(
+ grph_colors_adj,
+ adj_container,
+ &path_mode->mode_timing->crtc_timing,
+ disp_path,
+ adj_id,
+ gamut,
+ regamma,
+ color_control))
+ goto adj_color_control_fail;
+
+ color_control->surface_pixel_format =
+ path_mode->pixel_format;
+
+ result = dal_hw_sequencer_set_color_control_adjustment(
+ grph_colors_adj->hws,
+ dal_display_path_get_controller(disp_path),
+ color_control);
+
+ if (result == HWSS_RESULT_OK) {
+ if (grph_colors_adj->regamma_updated) {
+ enum ds_return ret;
+
+ if (!dal_adj_container_get_regamma_copy(
+ adj_container,
+ old_regamma))
+ goto adj_color_control_fail;
+
+ dal_adj_container_set_regamma(
+ adj_container,
+ regamma);
+ ret = dal_ds_dispatch_set_gamma_adjustment(
+ grph_colors_adj->ds,
+ display_index,
+ ADJ_ID_GAMMA_RAMP,
+ dal_ds_dispatch_get_current_gamma(
+ grph_colors_adj->ds,
+ display_index,
+ ADJ_ID_GAMMA_RAMP));
+ if (ret != DS_SUCCESS)
+ dal_adj_container_set_regamma(
+ adj_container,
+ regamma);
+ }
+ }
+ color_space =
+ dal_ds_translation_color_space_from_hw_color_space(
+ color_control->color_space);
+ dal_ds_dispatch_update_adj_container_for_path_with_color_space(
+ grph_colors_adj->ds,
+ display_index,
+ color_space);
+ }
+ dal_grph_colors_group_synch_color_temperature_with_gamut(
+ grph_colors_adj,
+ adj_container);
+ return DS_SUCCESS;
+
+adj_color_control_fail:
+ dal_free(old_regamma);
+old_regamma_fail:
+ dal_free(regamma);
+regamma_fail:
+ dal_free(gamut);
+gamut_fail:
+ dal_free(color_control);
+
+ return DS_ERROR;
+}
+
+enum ds_return dal_grph_colors_group_get_color_gamut(
+ struct grph_colors_group *grph_colors_adj,
+ struct display_path *disp_path,
+ const struct ds_gamut_reference_data *ref,
+ struct ds_get_gamut_data *data)
+{
+ enum ds_return ret;
+ uint32_t display_index;
+ struct adj_container *adj_container = NULL;
+ struct adjustment_info *temperature_src = NULL;
+ const struct display_characteristics *disp_char = NULL;
+ struct color_characteristic color_charact = {{0 } };
+ struct gamut_data gamut_data;
+ enum adjustment_id adj_id;
+ struct fixed31_32 result;
+
+ if (!disp_path)
+ return DS_ERROR;
+ display_index = dal_display_path_get_display_index(
+ disp_path);
+
+ adj_container = dal_ds_dispatch_get_adj_container_for_path(
+ grph_colors_adj->ds, display_index);
+ if (!adj_container)
+ return DS_ERROR;
+
+ if (!dal_hw_sequencer_is_support_custom_gamut_adj(
+ grph_colors_adj->hws,
+ disp_path,
+ HW_GRAPHIC_SURFACE))
+ return DS_ERROR;
+
+ dal_memset(&gamut_data, 0, sizeof(gamut_data));
+ if (!dal_ds_translate_gamut_reference(
+ ref, &adj_id))
+ return DS_ERROR;
+
+ if (adj_id == ADJ_ID_GAMUT_DESTINATION) {
+ temperature_src = dal_adj_info_set_get_adj_info(
+ &adj_container->adj_info_set,
+ ADJ_ID_TEMPERATURE_SOURCE);
+ if (temperature_src != NULL &&
+ temperature_src->adj_data.ranged.cur ==
+ COLOR_TEMPERATURE_SOURCE_EDID) {
+
+ disp_char = dal_adj_container_get_disp_character(
+ adj_container);
+ if (!disp_char)
+ return DS_ERROR;
+ if (!dal_gamut_space_convert_edid_format_color_charact(
+ disp_char->color_characteristics,
+ &color_charact))
+ return DS_ERROR;
+ gamut_data.option.bits.CUSTOM_GAMUT_SPACE = 1;
+ gamut_data.option.bits.CUSTOM_WHITE_POINT = 1;
+
+ result = dal_fixed31_32_mul(
+ dal_fixed31_32_from_int(
+ (int64_t)GAMUT_DIVIDER),
+ color_charact.red_x);
+ gamut_data.gamut.custom.red_x =
+ dal_fixed31_32_floor(result);
+
+ result = dal_fixed31_32_mul(
+ dal_fixed31_32_from_int(
+ (int64_t)GAMUT_DIVIDER),
+ color_charact.red_y);
+ gamut_data.gamut.custom.red_y =
+ dal_fixed31_32_floor(result);
+
+ result = dal_fixed31_32_mul(
+ dal_fixed31_32_from_int(
+ (int64_t)GAMUT_DIVIDER),
+ color_charact.blue_x);
+ gamut_data.gamut.custom.blue_x =
+ dal_fixed31_32_floor(result);
+
+ result = dal_fixed31_32_mul(
+ dal_fixed31_32_from_int(
+ (int64_t)GAMUT_DIVIDER),
+ color_charact.blue_y);
+ gamut_data.gamut.custom.blue_y =
+ dal_fixed31_32_floor(result);
+
+ result = dal_fixed31_32_mul(
+ dal_fixed31_32_from_int(
+ (int64_t)GAMUT_DIVIDER),
+ color_charact.green_x);
+ gamut_data.gamut.custom.green_x =
+ dal_fixed31_32_floor(result);
+
+ result = dal_fixed31_32_mul(
+ dal_fixed31_32_from_int(
+ (int64_t)GAMUT_DIVIDER),
+ color_charact.green_y);
+ gamut_data.gamut.custom.green_y =
+ dal_fixed31_32_floor(result);
+
+ result = dal_fixed31_32_mul(
+ dal_fixed31_32_from_int(
+ (int64_t)GAMUT_DIVIDER),
+ color_charact.white_x);
+ gamut_data.white_point.custom.white_x =
+ dal_fixed31_32_floor(result);
+
+ result = dal_fixed31_32_mul(
+ dal_fixed31_32_from_int(
+ (int64_t)GAMUT_DIVIDER),
+ color_charact.white_y);
+ gamut_data.white_point.custom.white_y =
+ dal_fixed31_32_floor(result);
+
+ ret = DS_SUCCESS;
+ }
+ }
+ if (ret != DS_SUCCESS)
+ if (!dal_adj_container_get_gamut(
+ adj_container,
+ adj_id,
+ &gamut_data))
+ return DS_ERROR;
+ if (!dal_ds_translate_internal_gamut_to_external_parameter(
+ &gamut_data,
+ &data->gamut))
+ return DS_ERROR;
+ return ret;
+}
+
+enum ds_return dal_grph_colors_group_get_color_gamut_info(
+ struct grph_colors_group *grph_colors_adj,
+ struct display_path *disp_path,
+ const struct ds_gamut_reference_data *ref,
+ struct ds_gamut_info *data)
+{
+ if (!disp_path)
+ return DS_ERROR;
+
+ if (!dal_hw_sequencer_is_support_custom_gamut_adj(
+ grph_colors_adj->hws,
+ disp_path,
+ HW_GRAPHIC_SURFACE))
+ return DS_ERROR;
+
+ if (!dal_gamut_space_get_supported_gamuts(data))
+ return DS_ERROR;
+
+ return DS_SUCCESS;
+}
+
+enum ds_return dal_grph_colors_group_get_regamma_lut(
+ struct grph_colors_group *grph_colors_adj,
+ struct display_path *disp_path,
+ struct ds_regamma_lut *data)
+{
+ uint32_t display_index;
+ struct adj_container *adj_container = NULL;
+ const struct ds_regamma_lut *regamma = NULL;
+
+ if (!disp_path)
+ return DS_ERROR;
+ display_index = dal_display_path_get_display_index(
+ disp_path);
+ adj_container = dal_ds_dispatch_get_adj_container_for_path(
+ grph_colors_adj->ds, display_index);
+ if (!adj_container)
+ return DS_ERROR;
+
+ if (!dal_hw_sequencer_is_support_custom_gamma_coefficients(
+ grph_colors_adj->hws,
+ disp_path,
+ HW_GRAPHIC_SURFACE))
+ return DS_ERROR;
+
+ regamma = dal_adj_container_get_regamma(adj_container);
+ if (!regamma)
+ return DS_ERROR;
+
+ dal_ds_translate_regamma_to_external(regamma, data);
+ return DS_SUCCESS;
+}
+
+enum ds_return dal_grph_colors_group_set_regamma_lut(
+ struct grph_colors_group *grph_colors_adj,
+ struct display_path *disp_path,
+ const struct ds_regamma_lut *data)
+{
+ uint32_t display_index;
+ enum ds_return ret;
+ struct adj_container *adj_container = NULL;
+ struct ds_regamma_lut *regamma = NULL;
+ struct ds_regamma_lut *old_regamma = NULL;
+ const struct raw_gamma_ramp *ramp = NULL;
+ struct gamut_data original_gamut = {{0 } };
+ struct gamut_data updated_gamut = {{0 } };
+ bool updated_gamut_dst = false;
+
+ if (!disp_path)
+ return DS_ERROR;
+ display_index = dal_display_path_get_display_index(
+ disp_path);
+ adj_container = dal_ds_dispatch_get_adj_container_for_path(
+ grph_colors_adj->ds, display_index);
+ if (!adj_container)
+ return DS_ERROR;
+
+ if (data->flags.bits.GAMMA_FROM_EDID_EX == 1 ||
+ data->flags.bits.COEFF_FROM_EDID == 1)
+ return DS_ERROR;
+
+ if (!dal_hw_sequencer_is_support_custom_gamma_coefficients(
+ grph_colors_adj->hws,
+ disp_path,
+ HW_GRAPHIC_SURFACE))
+ return DS_ERROR;
+
+ regamma = dal_alloc(sizeof(*regamma));
+ if (!regamma)
+ goto regamma_fail;
+
+ old_regamma = dal_alloc(sizeof(*old_regamma));
+ if (!old_regamma)
+ goto old_regamma_fail;
+
+ ramp = dal_ds_dispatch_get_current_gamma(
+ grph_colors_adj->ds,
+ display_index,
+ ADJ_ID_GAMMA_RAMP);
+ if (!dal_adj_container_get_regamma_copy(
+ adj_container,
+ old_regamma))
+ goto regamma_copy_fail;
+
+ dal_memmove(regamma, old_regamma, sizeof(*regamma));
+
+ if (!dal_ds_translate_regamma_to_internal(
+ data, regamma))
+ goto regamma_copy_fail;
+
+ if (!dal_adj_container_get_gamut(
+ adj_container,
+ ADJ_ID_GAMUT_DESTINATION,
+ &original_gamut))
+ goto regamma_copy_fail;
+
+ if (!dal_adj_container_set_regamma(
+ adj_container,
+ regamma))
+ goto regamma_copy_fail;
+
+ updated_gamut_dst = dal_grph_colors_group_update_gamut(
+ grph_colors_adj,
+ disp_path,
+ adj_container);
+
+ ret = dal_ds_dispatch_set_gamma_adjustment(
+ grph_colors_adj->ds,
+ display_index,
+ ADJ_ID_GAMMA_RAMP_REGAMMA_UPDATE,
+ ramp);
+
+ if (ret != DS_SUCCESS) {
+ if (updated_gamut_dst)
+ dal_adj_container_update_gamut(
+ adj_container,
+ ADJ_ID_GAMUT_DESTINATION,
+ &original_gamut);
+ if (!dal_adj_container_set_regamma(
+ adj_container,
+ old_regamma))
+ goto regamma_copy_fail;
+ } else {
+ if (!dal_adj_container_get_gamut(
+ adj_container,
+ ADJ_ID_GAMUT_DESTINATION,
+ &updated_gamut))
+ goto regamma_copy_fail;
+
+ return ret;
+ }
+
+regamma_copy_fail:
+ dal_free(old_regamma);
+old_regamma_fail:
+ dal_free(regamma);
+regamma_fail:
+ return DS_ERROR;
+}
+
+enum ds_return dal_grph_colors_group_update_gamut(
+ struct grph_colors_group *grph_colors_adj,
+ struct display_path *disp_path,
+ struct adj_container *adj_container)
+{
+ struct gamut_parameter *gamut = NULL;
+ enum signal_type signal;
+ const struct adjustment_info *temperature = NULL;
+ const struct adjustment_info *temperature_src = NULL;
+ const struct ds_regamma_lut *const_regamma = NULL;
+
+ if (!disp_path)
+ return false;
+
+ signal = dal_display_path_get_query_signal(
+ disp_path, SINK_LINK_INDEX);
+ if (signal == SIGNAL_TYPE_HDMI_TYPE_A)
+ return false;
+
+ gamut = dal_alloc(sizeof(*gamut));
+ if (!gamut)
+ return false;
+
+ temperature = dal_adj_info_set_get_adj_info(
+ &adj_container->adj_info_set,
+ ADJ_ID_TEMPERATURE);
+ temperature_src = dal_adj_info_set_get_adj_info(
+ &adj_container->adj_info_set,
+ ADJ_ID_TEMPERATURE_SOURCE);
+ if (temperature == NULL ||
+ temperature->adj_data.ranged.cur == -1)
+ goto gamut_fail;
+
+ gamut->source = ((temperature_src != NULL) &&
+ (temperature_src->adj_data.ranged.cur ==
+ COLOR_TEMPERATURE_SOURCE_EDID)) ?
+ GAMUT_SPACE_SOURCE_EDID :
+ GAMUT_SPACE_SOURCE_USER_GAMUT;
+ if (gamut->source != GAMUT_SPACE_SOURCE_USER_GAMUT)
+ goto gamut_fail;
+
+ if (!dal_adj_container_get_gamut(
+ adj_container,
+ ADJ_ID_GAMUT_SOURCE_GRPH,
+ &gamut->gamut_src))
+ goto gamut_fail;
+
+ if (!dal_adj_container_get_gamut(
+ adj_container,
+ ADJ_ID_GAMUT_DESTINATION,
+ &gamut->gamut_dst))
+ goto gamut_fail;
+
+ const_regamma = dal_adj_container_get_regamma(
+ adj_container);
+ if (!const_regamma)
+ goto gamut_fail;
+ dal_memmove(&gamut->regamma, const_regamma, sizeof(gamut->regamma));
+ {
+ union update_color_flags flags = {0};
+
+ if (!dal_gamut_space_update_gamut(
+ gamut, false, &flags))
+ goto gamut_fail;
+ if (flags.bits.GAMUT_DST == 1)
+ return dal_adj_container_update_gamut(
+ adj_container,
+ ADJ_ID_GAMUT_DESTINATION,
+ &gamut->gamut_dst);
+ }
+
+gamut_fail:
+ dal_free(gamut);
+ return false;
+}
+
+static bool grph_colors_group_construct(
+ struct grph_colors_group *grph_colors_adj,
+ struct grph_colors_group_init_data *init_data)
+{
+ if (!init_data)
+ return false;
+
+ grph_colors_adj->ds = init_data->ds;
+ grph_colors_adj->hws = init_data->hws;
+ grph_colors_adj->dal_context = init_data->dal_context;
+
+ return true;
+}
+
+struct grph_colors_group *dal_grph_colors_group_create(
+ struct grph_colors_group_init_data *init_data)
+{
+ struct grph_colors_group *grph_colors_adj = NULL;
+
+ grph_colors_adj = dal_alloc(sizeof(*grph_colors_adj));
+
+ if (!grph_colors_adj)
+ return NULL;
+
+ if (grph_colors_group_construct(grph_colors_adj, init_data))
+ return grph_colors_adj;
+
+ dal_free(grph_colors_adj);
+
+ return NULL;
+}
+
+static void destruct(
+ struct grph_colors_group *grph_colors_adj)
+{
+
+}
+
+void dal_grph_colors_adj_group_destroy(
+ struct grph_colors_group **grph_colors_adj)
+{
+ if (grph_colors_adj == NULL || *grph_colors_adj == NULL)
+ return;
+ destruct(*grph_colors_adj);
+ dal_free(*grph_colors_adj);
+ *grph_colors_adj = NULL;
+}
diff --git a/drivers/gpu/drm/amd/dal/display_service/grph_colors_group.h b/drivers/gpu/drm/amd/dal/display_service/grph_colors_group.h
new file mode 100644
index 000000000000..619c7aae4652
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/grph_colors_group.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2015 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_GRPH_COLORS_GROUP_H__
+#define __DAL_GRPH_COLORS_GROUP_H__
+
+#include "include/adjustment_types.h"
+
+struct grph_colors_group;
+struct crtc_timing;
+struct display_path;
+struct adj_container;
+struct gamut_parameter;
+
+#define PIXEL_CLOCK 27030
+
+struct grph_colors_group {
+ struct ds_dispatch *ds;
+ struct hw_sequencer *hws;
+ struct dal_context *dal_context;
+ bool regamma_updated;
+ bool gamut_dst_updated;
+ bool gamut_src_updated;
+};
+
+struct grph_colors_group_init_data {
+ struct ds_dispatch *ds;
+ struct hw_sequencer *hws;
+ struct dal_context *dal_context;
+};
+
+enum ds_color_space dal_grph_colors_group_get_color_space(
+ struct grph_colors_group *grph_colors_adj,
+ const struct crtc_timing *timing,
+ const struct display_path *disp_path,
+ struct adj_container *adj_container);
+
+enum ds_return dal_grph_colors_group_set_adjustment(
+ struct grph_colors_group *grph_colors_adj,
+ struct display_path *disp_path,
+ enum adjustment_id adj_id,
+ uint32_t value);
+
+bool dal_grph_colors_group_compute_hw_adj_color_control(
+ struct grph_colors_group *grph_colors_adj,
+ struct adj_container *adj_container,
+ const struct crtc_timing *timing,
+ struct display_path *disp_path,
+ enum adjustment_id adj_id,
+ struct gamut_parameter *gamut,
+ struct ds_regamma_lut *regamma,
+ struct hw_adjustment_color_control *color_control);
+
+bool dal_grph_colors_group_build_color_control_adj(
+ struct grph_colors_group *grph_colors_adj,
+ const struct path_mode *mode,
+ struct display_path *disp_path,
+ struct hw_adjustment_set *set);
+
+enum ds_color_space dal_grph_colors_group_build_default_color_space(
+ struct grph_colors_group *grph_colors_adj,
+ const struct crtc_timing *timing,
+ const struct display_path *disp_path,
+ enum ds_color_space hdmi_request_color_space);
+
+enum ds_color_space dal_grph_colors_group_adjust_color_space(
+ struct grph_colors_group *grph_colors_adj,
+ enum ds_color_space color_space,
+ bool rgb_limited);
+
+bool dal_grph_colors_group_synch_color_temperature_with_gamut(
+ struct grph_colors_group *grph_colors_adj,
+ struct adj_container *adj_container);
+
+bool dal_grph_colors_group_synch_gamut_with_color_temperature(
+ struct grph_colors_group *grph_colors_adj,
+ struct adj_container *adj_container);
+
+bool dal_grph_colors_group_get_color_temperature(
+ struct grph_colors_group *grph_colors_adj,
+ struct adj_container *adj_container,
+ int32_t *temp);
+
+enum ds_return dal_grph_colors_group_set_color_graphics_gamut(
+ struct grph_colors_group *grph_colors_adj,
+ struct display_path *disp_path,
+ struct gamut_data *gamut_data,
+ enum adjustment_id adj_id,
+ bool apply_to_hw);
+
+enum ds_return dal_grph_colors_group_update_gamut(
+ struct grph_colors_group *grph_colors_adj,
+ struct display_path *disp_path,
+ struct adj_container *adj_container);
+
+struct grph_colors_group *dal_grph_colors_group_create(
+ struct grph_colors_group_init_data *init_data);
+
+void dal_grph_colors_adj_group_destroy(
+ struct grph_colors_group **grph_colors_adj);
+
+#endif /* __DAL_GRPH_COLORS_GROUP_H__ */
diff --git a/drivers/gpu/drm/amd/dal/display_service/path_mode_set.c b/drivers/gpu/drm/amd/dal/display_service/path_mode_set.c
new file mode 100644
index 000000000000..55e040d63ee2
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/path_mode_set.c
@@ -0,0 +1,220 @@
+/*
+ * 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 */
+#include "dal_services.h"
+#include "include/set_mode_interface.h"
+#include "include/hw_sequencer_types.h"
+#include "ds_dispatch.h"
+
+/* Create path mode set */
+struct path_mode_set *dal_pms_create()
+{
+ struct path_mode_set *set;
+
+ set = dal_alloc(sizeof(struct path_mode_set));
+
+ if (set == NULL)
+ return NULL;
+
+ if (dal_pms_construct(set))
+ return set;
+
+ dal_free(set);
+ BREAK_TO_DEBUGGER();
+ return NULL;
+}
+
+void dal_pms_destroy(struct path_mode_set **pms)
+{
+ if (!pms || !*pms) {
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+
+ dal_free(*pms);
+ *pms = NULL;
+}
+
+/* Create a copy of given path mode set */
+struct path_mode_set *dal_pms_copy(const struct path_mode_set *copy)
+{
+ struct path_mode_set *set = NULL;
+
+ if (copy == NULL) {
+ BREAK_TO_DEBUGGER();
+ return NULL;
+ }
+
+ set = dal_alloc(sizeof(struct path_mode_set));
+
+ if (set == NULL)
+ return NULL;
+
+ if (dal_pms_construct(set)) {
+ uint32_t i = 0;
+
+ set->count = copy->count;
+ set->control_flags.all = copy->control_flags.all;
+
+ for (i = 0; i < set->count; i++)
+ set->path_mode_set[i] = copy->path_mode_set[i];
+
+ return set;
+ }
+
+ dal_free(set);
+ BREAK_TO_DEBUGGER();
+ return NULL;
+
+
+}
+
+/* Constructor for path mode set */
+bool dal_pms_construct(struct path_mode_set *set)
+{
+ if (set == NULL)
+ return false;
+
+ set->count = 0;
+ set->control_flags.all = 0;
+
+ return true;
+}
+
+/* Add a path mode into the set */
+bool dal_pms_add_path_mode(
+ struct path_mode_set *set,
+ const struct path_mode *path_mode)
+{
+ if (set->count >= MAX_COFUNC_PATH)
+ return false;
+
+ /* Check if display index is already in the set */
+ if (dal_pms_get_path_mode_for_display_index(
+ set, path_mode->display_path_index) != NULL)
+ return false;
+
+ set->path_mode_set[set->count] = *path_mode;
+ set->count++;
+
+ return true;
+}
+
+/* Get number of path modes in the set */
+uint32_t dal_pms_get_path_mode_num(const struct path_mode_set *set)
+{
+ if (set == NULL) {
+ BREAK_TO_DEBUGGER();
+ return 0;
+ }
+ return set->count;
+}
+
+/* Return the path mode at the index */
+const struct path_mode *dal_pms_get_path_mode_at_index(
+ const struct path_mode_set *set,
+ uint32_t index)
+{
+ if (index >= set->count)
+ return NULL;
+ else
+ return &set->path_mode_set[index];
+}
+
+/* Return the path mode for the given display index */
+const struct path_mode *dal_pms_get_path_mode_for_display_index(
+ const struct path_mode_set *set,
+ uint32_t index)
+{
+ uint32_t i;
+
+ for (i = 0; i < set->count; i++) {
+ if (set->path_mode_set[i].display_path_index == index)
+ return &set->path_mode_set[i];
+ }
+ return NULL;
+}
+
+/* Add control flag to keep display powered off */
+void dal_pms_keep_display_powered_off(
+ struct path_mode_set *set,
+ bool keep)
+{
+ set->control_flags.bits.KEEP_DISPLAY_POWERED_OFF = keep;
+}
+
+/* Return control flag if display needs to be kept powered off */
+bool dal_pms_is_display_power_off_required(const struct path_mode_set *set)
+{
+ return set->control_flags.bits.KEEP_DISPLAY_POWERED_OFF;
+}
+
+/* Add control flag to not use default underscan*/
+void dal_pms_fallback_remove_default_underscan(
+ struct path_mode_set *set,
+ bool lean)
+{
+ /* TODO: implementation */
+}
+
+/* Return control flag if default underscan is not used */
+bool dal_pms_is_fallback_no_default_underscan_enabled(
+ struct path_mode_set *set)
+{
+ return false;
+}
+
+/* Remove path mode at index from the set */
+bool dal_pms_remove_path_mode_at_index(
+ struct path_mode_set *set,
+ uint32_t index)
+{
+ if (index < set->count) {
+ uint32_t i = 0;
+
+ for (i = index; i < set->count; i++)
+ set->path_mode_set[i] = set->path_mode_set[i + 1];
+ set->count--;
+ } else
+ return false;
+
+ return true;
+}
+
+/* Remove path mode from the set if given mode is found */
+bool dal_pms_remove_path_mode(
+ struct path_mode_set *set,
+ struct path_mode *mode)
+{
+ uint32_t i;
+
+ for (i = 0; i < set->count; i++) {
+ if (&set->path_mode_set[i] == mode)
+ return dal_pms_remove_path_mode_at_index(set, i);
+ }
+
+ return false;
+}
diff --git a/drivers/gpu/drm/amd/dal/display_service/path_mode_set_with_data.c b/drivers/gpu/drm/amd/dal/display_service/path_mode_set_with_data.c
new file mode 100644
index 000000000000..43dd1e0a8758
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/path_mode_set_with_data.c
@@ -0,0 +1,308 @@
+/*
+ * 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 "include/plane_types.h"
+
+#include "path_mode_set_with_data.h"
+
+/* Set of path modes with corresponding data flags*/
+struct path_mode_set_with_data {
+ struct path_mode_set base;
+ struct mode_timing mode_timing[MAX_COFUNC_PATH];
+ struct active_path_data path_data[MAX_COFUNC_PATH];
+
+ struct vector plane_configs[MAX_COFUNC_PATH];
+};
+
+#define FROM_PMS(ptr) \
+ container_of((ptr), struct path_mode_set_with_data, base)
+
+/* Constructor for path mode set with data */
+static bool construct(struct path_mode_set_with_data *set)
+{
+ if (set == NULL)
+ return false;
+
+ if (!dal_pms_construct(&set->base))
+ return false;
+
+ return true;
+}
+
+/*
+ * Path mode set with data
+ */
+
+/* Create the set for path mode with data */
+struct path_mode_set_with_data *dal_pms_with_data_create()
+{
+ struct path_mode_set_with_data *set = NULL;
+
+ set = dal_alloc(sizeof(struct path_mode_set_with_data));
+
+ if (set == NULL)
+ return NULL;
+
+ if (construct(set))
+ return set;
+
+ dal_free(set);
+ BREAK_TO_DEBUGGER();
+ return NULL;
+}
+
+/* Add path mode with data into the set */
+bool dal_pms_with_data_add_path_mode_with_data(
+ struct path_mode_set_with_data *set,
+ const struct path_mode *mode,
+ const struct active_path_data *data)
+{
+ bool result = dal_pms_add_path_mode(&set->base, mode);
+ uint32_t index = set->base.count - 1;
+ const uint32_t preallocate_planes_num = 4;
+
+ if (result) {
+ set->mode_timing[index] = *mode->mode_timing;
+ set->base.path_mode_set[index].mode_timing =
+ &set->mode_timing[index];
+
+ set->path_data[index].current_underscan.x = 0;
+ set->path_data[index].current_underscan.y = 0;
+ set->path_data[index].current_underscan.width = 0;
+ set->path_data[index].current_underscan.height = 0;
+ set->path_data[index].flags.all = 0;
+ /* TODO: set->path_data[index].viewport_adjustment */
+
+ /* TODO: viewport_adjustment
+ uint32_t i = 0;
+ for (i = 0; i < HW_MAX_NUM_VIEW_PORTS; i++) {
+
+ }
+ */
+
+ if (data != NULL) {
+ set->path_data[index].ws_stereo_state =
+ data->ws_stereo_state;
+ set->path_data[index].gtc_group = data->gtc_group;
+ set->path_data[index].display_state.OUTPUT_ENABLED =
+ data->display_state.OUTPUT_ENABLED;
+ set->path_data[index].display_state.OUTPUT_BLANKED =
+ data->display_state.OUTPUT_BLANKED;
+ } else {
+ set->path_data[index].ws_stereo_state =
+ WS_STEREO_STATE_INACTIVE;
+ set->path_data[index].gtc_group = GTC_GROUP_DISABLED;
+ set->path_data[index].display_state.OUTPUT_ENABLED = 0;
+ set->path_data[index].display_state.OUTPUT_BLANKED = 0;
+ }
+
+ result = dal_vector_construct(
+ &set->plane_configs[index],
+ preallocate_planes_num,
+ sizeof(struct plane_config));
+
+ }
+
+ return result;
+}
+
+/* Get the data at index */
+struct active_path_data *dal_pms_with_data_get_path_data_at_index(
+ struct path_mode_set_with_data *set,
+ uint32_t index)
+{
+ if (index < set->base.count)
+ return &set->path_data[index];
+ return NULL;
+}
+
+/* Get the data for the given display index in the set*/
+struct active_path_data *dal_pms_with_data_get_path_data_for_display_index(
+ struct path_mode_set_with_data *set,
+ uint32_t index)
+{
+ uint32_t i;
+
+ for (i = 0; i < set->base.count; i++) {
+ if (set->base.path_mode_set[i].display_path_index == index)
+ return &set->path_data[i];
+ }
+
+ return NULL;
+}
+
+/* Get mode timing at index */
+const struct path_mode *dal_pms_with_data_get_path_mode_at_index(
+ struct path_mode_set_with_data *set,
+ uint32_t index)
+{
+ return dal_pms_get_path_mode_at_index(&set->base, index);
+}
+
+/* Get path mode for the given display index in the set */
+const struct path_mode *
+dal_pms_with_data_get_path_mode_for_display_index(
+ const struct path_mode_set_with_data *set,
+ uint32_t index)
+{
+ return dal_pms_get_path_mode_for_display_index(&set->base, index);
+}
+
+bool dal_pms_with_data_remove_path_mode_at_index(
+ struct path_mode_set_with_data *set_with_data,
+ uint32_t index)
+{
+ if (dal_pms_remove_path_mode_at_index(&set_with_data->base, index)) {
+ uint32_t i;
+
+ for (i = index; i < set_with_data->base.count; i++) {
+ set_with_data->mode_timing[i] =
+ set_with_data->mode_timing[i + 1];
+
+ set_with_data->base.path_mode_set[i].mode_timing =
+ &set_with_data->mode_timing[i];
+
+ set_with_data->path_data[i] =
+ set_with_data->path_data[i + 1];
+ dal_vector_destruct(&set_with_data->plane_configs[i]);
+ set_with_data->plane_configs[i] =
+ set_with_data->plane_configs[i + 1];
+ }
+
+ /* this is the case when we do not enter loop, so destructor
+ * should be called */
+ if (index == set_with_data->base.count)
+ dal_vector_destruct(
+ &set_with_data->plane_configs[index]);
+ } else
+ return false;
+
+ return true;
+}
+
+bool dal_pms_with_data_remove_path_mode_for_display_index(
+ struct path_mode_set_with_data *set_with_data,
+ uint32_t index)
+{
+ uint32_t i;
+
+ for (i = 0; i < set_with_data->base.count; i++) {
+ if (set_with_data->base.path_mode_set[i].display_path_index == index)
+ return dal_pms_with_data_remove_path_mode_at_index(
+ set_with_data,
+ i);
+ }
+
+ return false;
+}
+
+uint32_t dal_pms_with_data_get_path_mode_num(
+ const struct path_mode_set_with_data *set)
+{
+ return dal_pms_get_path_mode_num(&set->base);
+}
+
+static bool get_path_mode_index(
+ struct path_mode_set_with_data *set,
+ uint32_t display_index,
+ uint32_t *index)
+{
+ uint32_t i;
+
+ for (i = 0; i < set->base.count; ++i) {
+ if (set->base.path_mode_set[i].display_path_index ==
+ display_index) {
+ *index = i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+DAL_VECTOR_APPEND(plane_configs, const struct plane_config *)
+
+void dal_pms_with_data_add_plane_configs(
+ struct path_mode_set_with_data *set,
+ uint32_t display_index,
+ const struct plane_config *configs,
+ uint32_t planes_num)
+{
+ uint32_t i;
+ uint32_t index;
+
+ if (!get_path_mode_index(set, display_index, &index))
+ return;
+
+ for (i = 0; i < planes_num; ++i)
+ plane_configs_vector_append(
+ &set->plane_configs[index],
+ &configs[i]);
+}
+
+struct vector *dal_pms_with_data_get_plane_configs(
+ struct path_mode_set_with_data *set,
+ uint32_t display_index)
+{
+ uint32_t index;
+
+ if (!get_path_mode_index(set, display_index, &index))
+ return NULL;
+
+ return &set->plane_configs[index];
+}
+
+void dal_pms_with_data_clear_plane_configs(
+ struct path_mode_set_with_data *set,
+ uint32_t display_index)
+{
+ uint32_t index;
+
+ if (!get_path_mode_index(set, display_index, &index))
+ return;
+
+ dal_vector_clear(&set->plane_configs[index]);
+}
+
+static void destruct(struct path_mode_set_with_data *set)
+{
+ uint32_t i;
+
+ for (i = 0; i < dal_pms_get_path_mode_num(&set->base); ++i)
+ dal_vector_destruct(&set->plane_configs[i]);
+}
+
+void dal_pms_with_data_destroy(struct path_mode_set_with_data **set)
+{
+ if (!set || !*set)
+ return;
+
+ destruct(*set);
+ dal_free(*set);
+ *set = NULL;
+}
diff --git a/drivers/gpu/drm/amd/dal/display_service/path_mode_set_with_data.h b/drivers/gpu/drm/amd/dal/display_service/path_mode_set_with_data.h
new file mode 100644
index 000000000000..18d043c0b677
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/path_mode_set_with_data.h
@@ -0,0 +1,134 @@
+/*
+ * 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_PATH_MODE_SET_WITH_DATA_H__
+#define __DAL_PATH_MODE_SET_WITH_DATA_H__
+
+#include "include/set_mode_types.h"
+#include "include/display_service_types.h"
+#include "include/path_mode_set_interface.h"
+#include "include/timing_service_types.h"
+
+/* Data flags */
+struct active_path_data {
+ union active_data_flags {
+ struct {
+ uint32_t EXISTING:1;
+ uint32_t REPROGRAM_HW:1;
+ uint32_t ENABLE_HW:1;
+ uint32_t DISABLE_HW:1;
+ uint32_t KEEP_VCC_ON_DISABLE_HW:1;
+ uint32_t RESYNC_HW:1;
+ uint32_t POST_ACTION_DISPLAY_ON:1;
+ uint32_t TURN_OFF_BACK_END_AND_RX:1;
+ uint32_t VIEW_RES_CHANGED:1;
+ uint32_t TIMING_CHANGED:1;
+ uint32_t PIXEL_ENCODING_CHANGED:1;
+ uint32_t GAMUT_CHANGED:1;
+ uint32_t REDUCE_BLANK_ON:1;
+ uint32_t PENDING_DISPLAY_STEREO:1;
+ uint32_t SYNC_TIMING_SERVER:1;
+ uint32_t DISPLAY_PATH_INVALID:1;
+ uint32_t NO_DEFAULT_DOWN_SCALING:1;
+ uint32_t AUDIO_BANDWIDTH_CHANGED:1;
+ uint32_t SKIP_ENABLE:1;
+ uint32_t SKIP_RESET_HW:1;
+ } bits;
+
+ uint32_t all;
+ } flags;
+
+ struct display_state {
+ uint32_t OUTPUT_ENABLED:1;
+ uint32_t OUTPUT_BLANKED:1;
+ } display_state;
+
+ struct ds_underscan_desc current_underscan;
+ enum ws_stereo_state ws_stereo_state;
+ enum gtc_group gtc_group;
+ struct hw_get_viewport_x_adjustments *viewport_adjustment;
+ struct ranged_timing_preference_flags ranged_timing_pref_flags;
+};
+
+struct path_mode_set_with_data;
+
+/* Create the set for path mode with data */
+struct path_mode_set_with_data *dal_pms_with_data_create(void);
+
+void dal_pms_with_data_destroy(struct path_mode_set_with_data **set);
+
+/* Add path mode with data into the set */
+bool dal_pms_with_data_add_path_mode_with_data(
+ struct path_mode_set_with_data *set,
+ const struct path_mode *mode,
+ const struct active_path_data *data);
+
+/* Get the data at index */
+struct active_path_data *dal_pms_with_data_get_path_data_at_index(
+ struct path_mode_set_with_data *set,
+ uint32_t index);
+
+/* Get the data for the given display index in the set*/
+struct active_path_data *dal_pms_with_data_get_path_data_for_display_index(
+ struct path_mode_set_with_data *set,
+ uint32_t index);
+
+/* Get path mode at index */
+const struct path_mode *dal_pms_with_data_get_path_mode_at_index(
+ struct path_mode_set_with_data *set,
+ uint32_t index);
+
+/* Get path mode for the given display index in the set */
+const struct path_mode *
+dal_pms_with_data_get_path_mode_for_display_index(
+ const struct path_mode_set_with_data *set,
+ uint32_t index);
+
+uint32_t dal_pms_with_data_get_path_mode_num(
+ const struct path_mode_set_with_data *set);
+
+bool dal_pms_with_data_remove_path_mode_at_index(
+ struct path_mode_set_with_data *set_with_data,
+ uint32_t index);
+
+bool dal_pms_with_data_remove_path_mode_for_display_index(
+ struct path_mode_set_with_data *set_with_data,
+ uint32_t index);
+
+void dal_pms_with_data_add_plane_configs(
+ struct path_mode_set_with_data *set,
+ uint32_t display_index,
+ const struct plane_config *configs,
+ uint32_t planes_num);
+
+struct vector *dal_pms_with_data_get_plane_configs(
+ struct path_mode_set_with_data *set,
+ uint32_t display_index);
+
+void dal_pms_with_data_clear_plane_configs(
+ struct path_mode_set_with_data *set,
+ uint32_t display_index);
+
+#endif
diff --git a/drivers/gpu/drm/amd/dal/display_service/scaler_adj_group.c b/drivers/gpu/drm/amd/dal/display_service/scaler_adj_group.c
new file mode 100644
index 000000000000..ba894168dc76
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/scaler_adj_group.c
@@ -0,0 +1,944 @@
+/*
+ * 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/adjustment_interface.h"
+#include "include/hw_sequencer_interface.h"
+#include "include/hw_path_mode_set_interface.h"
+#include "include/hw_adjustment_types.h"
+#include "include/adjustment_types.h"
+#include "include/display_service_types.h"
+#include "include/logger_interface.h"
+#include "include/set_mode_types.h"
+#include "include/set_mode_interface.h"
+#include "include/dcs_types.h"
+#include "include/dcs_interface.h"
+#include "include/timing_service_types.h"
+#include "include/timing_service_interface.h"
+#include "include/display_path_interface.h"
+
+#include "ds_translation.h"
+#include "adjustment_container.h"
+#include "scaler_adj_group.h"
+
+/*to chk whether underscan can be applied to current timing*/
+static bool can_scaling_be_applied(
+ struct adj_container *container,
+ enum timing_standard timing_std,
+ enum timing_source timing_src,
+ enum adjustment_id adj_id,
+ enum underscan_reason reason)
+{
+ struct adjustment_info *info = NULL;
+ enum signal_type type;
+
+ if (!container)
+ return false;
+
+ if (adj_id != ADJ_ID_MULTIMEDIA_PASS_THROUGH) {
+ info = dal_adj_info_set_get_adj_info(
+ &container->adj_info_set,
+ ADJ_ID_MULTIMEDIA_PASS_THROUGH);
+ if (info) {
+ /*if indeed multimedia pass thru,we don't need apply
+ * underscan*/
+ if (info->adj_data.ranged.cur > 0)
+ return false;
+ }
+ }
+ type = dal_adj_container_get_signal_type(container);
+ if (dal_timing_service_is_ce_timing_standard(timing_std) ||
+ (dal_is_embedded_signal(type) && timing_std ==
+ TIMING_STANDARD_EXPLICIT)) {
+ if (timing_src != TIMING_SOURCE_CUSTOM &&
+ reason != UNDERSCAN_REASON_FALL_BACK)
+ return true;/*we will do underscan*/
+ }
+ return false;
+}
+
+static bool is_pass_thru_enabled(
+ const struct ds_adjustment_scaler *scaler_param,
+ const struct ds_underscan_parameter *underscan_param,
+ struct adj_container *container,
+ enum build_path_set_reason reason)
+{
+ const struct adjustment_info *info;
+ enum underscan_reason reason_for_underscan;
+
+ if (scaler_param->adjust_id == ADJ_ID_MULTIMEDIA_PASS_THROUGH &&
+ scaler_param->value > 0)
+ return true;
+
+ switch (reason) {
+ case BUILD_PATH_SET_REASON_FALLBACK_UNDERSCAN:
+ reason_for_underscan = UNDERSCAN_REASON_FALL_BACK;
+ break;
+ case BUILD_PATH_SET_REASON_SET_MODE:
+ reason_for_underscan = UNDERSCAN_REASON_PATCH_TIMING;
+ break;
+ case BUILD_PATH_SET_REASON_SET_ADJUSTMENT:
+ default:
+ reason_for_underscan = UNDERSCAN_REASON_SET_ADJUSTMENT;
+ break;
+ }
+
+ if (can_scaling_be_applied(
+ container,
+ scaler_param->timing_standard,
+ scaler_param->timing_source,
+ scaler_param->adjust_id,
+ reason_for_underscan)) {
+ info = dal_adj_info_set_get_adj_info(
+ &container->adj_info_set,
+ ADJ_ID_MULTIMEDIA_PASS_THROUGH);
+ if (!info)
+ return false;
+ if (info->adj_data.ranged.cur > 0)
+ return true;
+ }
+
+ return false;
+}
+
+static bool build_base_avi_info_frame_parameter(
+ const struct ds_adjustment_scaler *scaler_param,
+ const struct ds_underscan_parameter *underscan_param,
+ struct adj_container *container,
+ const struct hw_path_mode *hw_path_mode,
+ enum build_path_set_reason reason,
+ enum hw_scale_options *underscan_avi_rule)
+{
+ struct cea861_support cea861_support = {0};
+
+ if (hw_path_mode->mode.ds_info.cea_vic != 0)
+ if (is_pass_thru_enabled(
+ scaler_param, underscan_param, container, reason))
+ *underscan_avi_rule = HW_SCALE_OPTION_OVERSCAN;
+ else
+ *underscan_avi_rule = HW_SCALE_OPTION_UNDERSCAN;
+ else {
+ if (dal_adj_container_get_cea861_support(container,
+ &cea861_support) &&
+ cea861_support.features.UNDER_SCAN == 1)
+ *underscan_avi_rule = HW_SCALE_OPTION_UNDERSCAN;
+ else
+ *underscan_avi_rule = HW_SCALE_OPTION_UNKNOWN;
+ }
+ return true;
+}
+
+static bool build_avi_info_frame_parameter(
+ const struct ds_adjustment_scaler *scaler_param,
+ struct ds_underscan_parameter *underscan_param,
+ struct adj_container *container,
+ const struct hw_path_mode *hw_path_mode,
+ enum build_path_set_reason reason,
+ enum hw_scale_options *underscan_avi_rule)
+{
+ union cea_video_capability_data_block vcdb = { {0} };
+ bool result = false;
+
+ if (dal_adj_container_get_cea_video_cap_data_block(container, &vcdb)) {
+ if (hw_path_mode->mode.ds_info.DISPLAY_PREFERED_MODE == 1 &&
+ (vcdb.bits.S_PT0 != 0 || vcdb.bits.S_PT1 != 0)) {
+ if (vcdb.bits.S_PT0 == 1 && vcdb.bits.S_PT1 == 0)
+ *underscan_avi_rule = HW_SCALE_OPTION_OVERSCAN;
+ else if (vcdb.bits.S_PT0 == 0 && vcdb.bits.S_PT1 == 1)
+ *underscan_avi_rule = HW_SCALE_OPTION_UNDERSCAN;
+ else
+ result = build_base_avi_info_frame_parameter(
+ scaler_param,
+ underscan_param,
+ container,
+ hw_path_mode,
+ reason,
+ underscan_avi_rule);
+ } else {
+ if (hw_path_mode->mode.ds_info.cea_vic != 0) {
+ if (vcdb.bits.S_CE0 == 1 && vcdb.bits.S_CE1 == 0)
+ *underscan_avi_rule = HW_SCALE_OPTION_OVERSCAN;
+ else if (vcdb.bits.S_CE0 == 0 && vcdb.bits.S_CE1 == 1)
+ *underscan_avi_rule = HW_SCALE_OPTION_UNDERSCAN;
+ else
+ result = build_base_avi_info_frame_parameter(
+ scaler_param,
+ underscan_param,
+ container,
+ hw_path_mode,
+ reason,
+ underscan_avi_rule);
+ } else {
+ if (vcdb.bits.S_IT0 == 1 && vcdb.bits.S_IT1 == 0)
+ *underscan_avi_rule = HW_SCALE_OPTION_OVERSCAN;
+ else if (vcdb.bits.S_IT0 == 0 && vcdb.bits.S_IT1 == 1)
+ *underscan_avi_rule = HW_SCALE_OPTION_UNDERSCAN;
+ else
+ result = build_base_avi_info_frame_parameter(
+ scaler_param,
+ underscan_param,
+ container,
+ hw_path_mode,
+ reason,
+ underscan_avi_rule);
+ }
+ }
+ } else
+ result = build_base_avi_info_frame_parameter(
+ scaler_param,
+ underscan_param,
+ container,
+ hw_path_mode,
+ reason,
+ underscan_avi_rule);
+ return result;
+}
+
+/*we donot enable underscan on DP since architect decision*/
+static bool is_dp_underscan_disabled(
+ struct display_path *display_path,
+ uint32_t idx)
+{
+ if (display_path) {
+ enum signal_type signal =
+ dal_display_path_get_query_signal(
+ display_path,
+ SINK_LINK_INDEX);
+
+ if (dal_is_dp_signal(signal) ||
+ dal_is_dp_external_signal(signal))
+ return true;
+ }
+ return false;
+}
+
+static bool setup_parameter(
+ const struct hw_path_mode *hw_path_mode,
+ const struct ds_adjustment_scaler *scaler_param,
+ struct ds_underscan_parameter *underscan_param)
+{
+ if (scaler_param->flags.bits.IS_UNDERSCAN_DESC != 1 || !scaler_param ||
+ !hw_path_mode)
+ return false;
+
+ if (scaler_param->underscan_desc.width == 0 ||
+ scaler_param->underscan_desc.height == 0 ||
+ scaler_param->underscan_desc.width <
+ scaler_param->underscan_desc.x ||
+ scaler_param->underscan_desc.height <
+ scaler_param->underscan_desc.y)
+ return false;
+
+ if (scaler_param->underscan_desc.width >
+ hw_path_mode->mode.timing.h_addressable)
+ return false;
+
+ if (scaler_param->underscan_desc.height >
+ hw_path_mode->mode.timing.v_addressable)
+ return false;
+
+ dal_memset(underscan_param, 0, sizeof(*underscan_param));
+ underscan_param->type = DS_UNDERSCAN_TYPE_DIMENTIONS;
+ underscan_param->data.dimentions.data.width =
+ scaler_param->underscan_desc.width;
+ underscan_param->data.dimentions.data.height =
+ scaler_param->underscan_desc.height;
+ underscan_param->data.dimentions.data.position_x =
+ scaler_param->underscan_desc.x;
+ underscan_param->data.dimentions.data.position_y =
+ scaler_param->underscan_desc.y;
+ underscan_param->data.dimentions.modified_boarder_x =
+ hw_path_mode->mode.timing.h_addressable -
+ scaler_param->underscan_desc.width;
+ underscan_param->data.dimentions.modified_boarder_y =
+ hw_path_mode->mode.timing.v_addressable -
+ scaler_param->underscan_desc.height;
+
+ return true;
+
+}
+
+static void setup_parameters(
+ const struct hw_path_mode *hw_path_mode,
+ const struct ds_adjustment_scaler *scaler_param,
+ struct ds_overscan *overscan,
+ struct ds_underscan_parameter *underscan_param,
+ struct timing_info_parameter *timing_info)
+{
+ overscan->left = hw_path_mode->mode.overscan.left;
+ overscan->right = hw_path_mode->mode.overscan.right;
+ overscan->top = hw_path_mode->mode.overscan.top;
+ overscan->bottom = hw_path_mode->mode.overscan.bottom;
+ dal_memset(underscan_param, 0, sizeof(*underscan_param));
+ underscan_param->type = DS_UNDERSCAN_TYPE_PERCENT;
+ underscan_param->data.percent.old_dst_x =
+ hw_path_mode->mode.scaling_info.dst.width;
+ underscan_param->data.percent.old_dst_y =
+ hw_path_mode->mode.scaling_info.dst.height;
+ underscan_param->data.percent.percent_x =
+ (uint32_t)scaler_param->value;
+ underscan_param->data.percent.percent_y =
+ (uint32_t)scaler_param->value;
+
+ dal_memset(timing_info, 0, sizeof(*timing_info));
+ timing_info->timing = hw_path_mode->mode.timing;
+ timing_info->dst_width =
+ hw_path_mode->mode.scaling_info.dst.width;
+ timing_info->dst_height =
+ hw_path_mode->mode.scaling_info.dst.height;
+
+}
+
+
+static void extract_parameters(
+ const struct ds_adjustment_scaler *scaler_param,
+ const struct timing_info_parameter *timing_info,
+ const struct ds_overscan *overscan,
+ enum hw_scale_options underscan_avi_rule,
+ struct hw_path_mode *hw_path_mode)
+{
+ hw_path_mode->mode.overscan.left = overscan->left;
+ hw_path_mode->mode.overscan.right = overscan->right;
+ hw_path_mode->mode.overscan.top = overscan->top;
+ hw_path_mode->mode.overscan.bottom = overscan->bottom;
+ hw_path_mode->mode.scaling_info.dst.width =
+ timing_info->dst_width;
+ hw_path_mode->mode.scaling_info.dst.height =
+ timing_info->dst_height;
+ hw_path_mode->mode.underscan_rule = underscan_avi_rule;
+ hw_path_mode->mode.ds_info.position_x = overscan->left;
+ hw_path_mode->mode.ds_info.position_y = overscan->top;
+ hw_path_mode->mode.ds_info.TIMING_UNDERSCAN_PATCHED = 1;
+}
+
+static void update_underscan_bundle(
+ const struct ds_adjustment_scaler *scaler_param,
+ const struct underscan_adjustment_group *group,
+ const struct timing_info_parameter *timing_info,
+ struct ds_underscan_parameter *underscan)
+{
+ switch (group->id_requested) {
+ case ADJ_ID_UNDERSCAN:
+ if (scaler_param->flags.bits.IS_TV == 1 &&
+ group->current_underscan_auto == 0) {
+ underscan->type = DS_UNDERSCAN_TYPE_DIMENTIONS;
+ underscan->data.dimentions.data.width =
+ group->current_underscan_desc.width;
+ underscan->data.dimentions.data.height =
+ group->current_underscan_desc.height;
+ underscan->data.dimentions.data.position_x =
+ group->current_underscan_desc.x;
+ underscan->data.dimentions.data.position_y =
+ group->current_underscan_desc.y;
+ underscan->data.dimentions.modified_boarder_x =
+ timing_info->timing.h_addressable -
+ group->current_underscan_desc.width;
+ underscan->data.dimentions.modified_boarder_y =
+ timing_info->timing.v_addressable -
+ group->current_underscan_desc.height;
+ } else {
+ underscan->data.percent.percent_x =
+ (uint32_t)group->requested_value;
+ underscan->data.percent.percent_y =
+ (uint32_t)group->requested_value;
+ }
+ break;
+ case ADJ_ID_UNDERSCAN_TYPE:
+ if (group->requested_value == 0) {
+ underscan->type = DS_UNDERSCAN_TYPE_DIMENTIONS;
+ underscan->data.dimentions.data.width =
+ group->current_underscan_desc.width;
+ underscan->data.dimentions.data.height =
+ group->current_underscan_desc.height;
+ underscan->data.dimentions.data.position_x =
+ group->current_underscan_desc.x;
+ underscan->data.dimentions.data.position_y =
+ group->current_underscan_desc.y;
+ underscan->data.dimentions.modified_boarder_x =
+ timing_info->timing.h_addressable -
+ group->current_underscan_desc.width;
+ underscan->data.dimentions.modified_boarder_y =
+ timing_info->timing.v_addressable -
+ group->current_underscan_desc.height;
+ } else {
+ underscan->data.percent.percent_x =
+ (uint32_t)group->current_percent_x;
+ underscan->data.percent.percent_y =
+ (uint32_t)group->current_percent_y;
+ }
+ break;
+ default:
+ break;
+ }
+
+}
+
+static bool calculate_underscan(
+ const struct ds_underscan_parameter *underscan_param,
+ uint32_t *new_dest_x,
+ uint32_t *new_dest_y,
+ struct ds_overscan *overscan)
+{
+ uint32_t underscan_x;
+ uint32_t underscan_y;
+ uint32_t underscan_x2;
+ uint32_t underscan_y2;
+
+ if (!underscan_param || !overscan || !new_dest_x || !new_dest_y)
+ return false;
+
+ if (underscan_param->type != DS_UNDERSCAN_TYPE_PERCENT &&
+ underscan_param->type != DS_UNDERSCAN_TYPE_DIMENTIONS)
+ return false;
+
+ if (underscan_param->type == DS_UNDERSCAN_TYPE_PERCENT) {
+ if (underscan_param->data.percent.old_dst_x == 0 ||
+ underscan_param->data.percent.old_dst_y == 0)
+ return false;
+ underscan_x = underscan_param->data.percent.old_dst_x *
+ underscan_param->data.percent.percent_x / 100;
+ underscan_y = underscan_param->data.percent.old_dst_y *
+ underscan_param->data.percent.percent_y / 100;
+
+ if (underscan_param->data.percent.old_dst_x <= underscan_x ||
+ underscan_param->data.percent.old_dst_y <= underscan_y)
+ return false;
+
+ *new_dest_x = underscan_param->data.percent.old_dst_x - underscan_x;
+ *new_dest_y = underscan_param->data.percent.old_dst_y - underscan_y;
+ underscan_x2 = underscan_x>>1;
+ underscan_x -= underscan_x2;
+
+ underscan_y2 = underscan_y>>1;
+ underscan_y -= underscan_y2;
+
+ overscan->left += underscan_x;
+ overscan->right += underscan_x2;
+ overscan->bottom += underscan_y;
+ overscan->top += underscan_y2;
+
+ }
+ /* this underscan is not centered!*/
+ else {
+ if (underscan_param->data.dimentions.data.width == 0 ||
+ underscan_param->data.dimentions.data.height == 0)
+ return false;
+ overscan->left +=
+ underscan_param->data.dimentions.data.position_x;
+ overscan->right +=
+ underscan_param->data.dimentions.modified_boarder_x;
+ overscan->right = overscan->right >=
+ underscan_param->data.dimentions.data.position_y ?
+ overscan->bottom - underscan_param->
+ data.dimentions.data.position_y : 0;
+ *new_dest_x = underscan_param->data.dimentions.data.width;
+ *new_dest_y = underscan_param->data.dimentions.data.height;
+ }
+ if (overscan->left & 0x01) {
+ overscan->left--;
+ overscan->right++;
+ }
+ /*Top should be even number at interlace mode*/
+ if (overscan->top & 0x01) {
+ overscan->top--;
+ overscan->bottom++;
+ }
+ return true;
+}
+
+bool dal_scaler_adj_group_build_scaler_parameter(
+ const struct path_mode *path_mode,
+ struct adj_container *container,
+ enum build_path_set_reason reason,
+ enum adjustment_id adjust_id,
+ int32_t value,
+ const struct ds_underscan_desc *underscan_desc,
+ const struct display_path *display_path,
+ struct ds_adjustment_scaler *param)
+{
+ struct dcs *dcs = dal_display_path_get_dcs(display_path);
+ struct dcs_stereo_3d_features feature;
+
+ if (!display_path || !path_mode || !dcs)
+ return false;
+ dal_memset(param, 0, sizeof(*param));
+ param->timing_source = path_mode->mode_timing->
+ mode_info.timing_source;
+ param->timing_standard = path_mode->mode_timing->crtc_timing.
+ timing_standard;
+ param->display_index = path_mode->display_path_index;
+ if (path_mode->view_3d_format != VIEW_3D_FORMAT_NONE) {
+ enum timing_3d_format format =
+ path_mode->mode_timing->crtc_timing.timing_3d_format;
+ feature = dal_dcs_get_stereo_3d_features(dcs, format);
+ if (feature.flags.SUPPORTED && !feature.flags.SCALING)
+ return false;
+ }
+
+ if (reason == BUILD_PATH_SET_REASON_SET_ADJUSTMENT) {
+ if (dal_adj_container_get_default_underscan_allow(container))
+ return false;
+ param->flags.bits.IS_FOR_SET_MODE = 0;
+ param->adjust_id = adjust_id;
+ param->value = value;
+ if (underscan_desc) {
+ param->underscan_desc = *underscan_desc;
+ param->flags.bits.IS_UNDERSCAN_DESC = 1;
+ }
+ } else {
+ param->flags.bits.IS_FOR_SET_MODE = 1;
+ param->adjust_id = ADJ_ID_UNDERSCAN;
+ param->value = 0;
+ }
+ return true;
+}
+
+static bool build_underscan_bundle(
+ const struct ds_adjustment_scaler *param,
+ struct adj_container *container,
+ const struct timing_info_parameter *timing_info,
+ struct underscan_adjustment_group *group)
+{
+ struct adjustment_info *mm_pass_thur;
+ struct adjustment_info *underscan;
+
+ dal_memset(group, 0, sizeof(*group));
+ group->id_overscan = ADJ_ID_OVERSCAN;
+ group->id_underscan = ADJ_ID_UNDERSCAN;
+ group->id_underscan_auto = ADJ_ID_UNDERSCAN_TYPE;
+ group->id_multi_media_pass_thru = ADJ_ID_MULTIMEDIA_PASS_THROUGH;
+
+ group->id_requested = param->adjust_id;
+ group->requested_value = param->value;
+
+ if (!param || !container || !timing_info)
+ return false;
+ underscan = dal_adj_info_set_get_adj_info(
+ &container->adj_info_set,
+ group->id_underscan);
+ if (!underscan)
+ return false;
+
+ mm_pass_thur = dal_adj_info_set_get_adj_info(
+ &container->adj_info_set,
+ group->id_multi_media_pass_thru);
+
+
+ group->current_percent_x = underscan->adj_data.ranged.cur;
+ group->current_percent_y = underscan->adj_data.ranged.cur;
+
+ if (mm_pass_thur)
+ group->current_multi_media_pass_thru =
+ mm_pass_thur->adj_data.ranged.cur;
+ else
+ group->current_multi_media_pass_thru = 0;
+ if (param->flags.bits.IS_FOR_SET_MODE == 1)
+ group->requested_value = group->current_percent_x;
+
+ return true;
+}
+
+static bool build_underscan_parameters(
+ const struct ds_adjustment_scaler *param,
+ struct adj_container *container,
+ enum build_path_set_reason reason,
+ struct ds_underscan_parameter *underscan_param,
+ struct timing_info_parameter *timing_info,
+ struct ds_overscan *overscan)
+{
+ struct underscan_adjustment_group group;
+
+ if (!build_underscan_bundle(
+ param,
+ container,
+ timing_info,
+ &group))
+ return false;
+ /*update parameter if required*/
+ update_underscan_bundle(
+ param,
+ &group,
+ timing_info,
+ underscan_param);
+ /*calculate underscan and new destination*/
+ if (!calculate_underscan(
+ underscan_param,
+ &timing_info->dst_width,
+ &timing_info->dst_height,
+ overscan))
+ return false;
+
+ return true;
+}
+
+static struct hw_path_mode *find_hw_path_mode(
+ const struct display_path *display_path,
+ struct hw_path_mode_set *hw_pms)
+{
+ uint32_t i;
+ uint32_t num_of_path;
+ struct hw_path_mode *mode = NULL;
+ struct hw_path_mode *local_mode;
+
+ num_of_path = dal_hw_path_mode_set_get_paths_number(hw_pms);
+ for (i = 0; i < num_of_path; i++) {
+ local_mode = dal_hw_path_mode_set_get_path_by_index(hw_pms, i);
+ if (local_mode && local_mode->display_path == display_path) {
+ mode = local_mode;
+ break;
+ }
+ }
+ return mode;
+}
+
+static bool build_hw_path_set_for_adjustment(
+ struct ds_dispatch *ds,
+ const struct ds_adjustment_scaler *param,
+ const struct display_path *display_path,
+ uint32_t disp_index,
+ struct hw_path_mode_set *hw_pms)
+{
+ struct adjustment_params adj_param;
+
+ if (!param || !display_path || !hw_pms)
+ return false;
+
+ dal_memset(&adj_param, 0, sizeof(struct adjustment_params));
+ adj_param.affected_path = display_path;
+ adj_param.action = ADJUSTMENT_ACTION_SET_ADJUSTMENT;
+ adj_param.params.type = ADJUSTMENT_PAR_TYPE_TIMING;
+ adj_param.params.timings.ajd_id = param->adjust_id;
+ adj_param.params.timings.adj_id_hw = HW_ADJUSTMENT_ID_OVERSCAN;
+ if (param->adjust_id == ADJ_ID_UNDERSCAN_TYPE)
+ adj_param.params.timings.ajd_id = ADJ_ID_UNDERSCAN;
+
+ return dal_ds_dispatch_build_hw_path_set_for_adjustment(
+ ds,
+ hw_pms,
+ &adj_param);
+}
+
+bool dal_scaler_adj_group_apply_scaling(
+ const struct ds_adjustment_scaler *param,
+ struct adj_container *container,
+ enum build_path_set_reason reason,
+ struct hw_path_mode *hw_path_mode)
+{
+ struct ds_overscan overscan;
+ struct ds_underscan_parameter parameter;
+ struct timing_info_parameter timing_info;
+ enum hw_scale_options underscan_avi_rule = HW_SCALE_OPTION_UNKNOWN;
+ enum underscan_reason reason_for_underscan;
+
+ build_avi_info_frame_parameter(
+ param,
+ NULL,
+ container,
+ hw_path_mode,
+ reason,
+ &hw_path_mode->mode.underscan_rule);
+
+ switch (reason) {
+ case BUILD_PATH_SET_REASON_FALLBACK_UNDERSCAN:
+ reason_for_underscan = UNDERSCAN_REASON_FALL_BACK;
+ break;
+ case BUILD_PATH_SET_REASON_SET_MODE:
+ reason_for_underscan = UNDERSCAN_REASON_PATCH_TIMING;
+ break;
+ case BUILD_PATH_SET_REASON_SET_ADJUSTMENT:
+ default:
+ reason_for_underscan = UNDERSCAN_REASON_SET_ADJUSTMENT;
+ break;
+ }
+
+ if (!can_scaling_be_applied(
+ container,
+ param->timing_standard,
+ param->timing_source,
+ param->adjust_id,
+ reason_for_underscan))
+ return false;
+
+ if (param->flags.bits.IS_UNDERSCAN_DESC == 0) {
+ if (param->flags.bits.IS_FOR_SET_MODE == 1 &&
+ param->adjust_id != ADJ_ID_UNDERSCAN)
+ return false;
+
+ if (is_dp_underscan_disabled(
+ hw_path_mode->display_path,
+ param->display_index))
+ return false;
+
+ setup_parameters(
+ hw_path_mode,
+ param,
+ &overscan,
+ &parameter,
+ &timing_info);
+ if (!build_underscan_parameters(
+ param,
+ container,
+ reason,
+ &parameter,
+ &timing_info,
+ &overscan))
+ return false;
+ } else {
+ dal_memset(
+ &parameter,
+ 0,
+ sizeof(struct ds_underscan_parameter));
+ dal_memset(
+ &timing_info,
+ 0,
+ sizeof(struct timing_info_parameter));
+ dal_memset(&overscan, 0, sizeof(struct ds_overscan));
+ timing_info.timing = hw_path_mode->mode.timing;
+ if (!setup_parameter(
+ hw_path_mode,
+ param,
+ &parameter))
+ return false;
+
+ if (!calculate_underscan(
+ &parameter,
+ &timing_info.dst_width,
+ &timing_info.dst_height,
+ &overscan))
+ return false;
+ }
+
+ build_avi_info_frame_parameter(
+ param,
+ &parameter,
+ container,
+ hw_path_mode,
+ reason,
+ &underscan_avi_rule);
+
+ extract_parameters(
+ param,
+ &timing_info,
+ &overscan,
+ underscan_avi_rule,
+ hw_path_mode);
+
+ return true;
+}
+
+static bool prepare_underscan(
+ struct ds_dispatch *ds,
+ const struct path_mode *path_mode,
+ const struct ds_adjustment_scaler *param,
+ struct adj_container *container,
+ const struct display_path *display_path,
+ struct hw_underscan_adjustment_data **hw_underscan_data,
+ struct hw_path_mode_set *hw_path_set)
+{
+ struct hw_underscan_adjustment hw_underscan_adj = { {0} };
+ struct hw_path_mode *hw_path_mode;
+ enum build_path_set_reason reason =
+ BUILD_PATH_SET_REASON_SET_ADJUSTMENT;
+ hw_path_set = dal_hw_path_mode_set_create();
+ if (!hw_path_set)
+ return false;
+ if (!build_hw_path_set_for_adjustment(
+ ds,
+ param,
+ display_path,
+ path_mode->display_path_index,
+ hw_path_set))
+ return false;
+
+
+ hw_path_mode = find_hw_path_mode(display_path, hw_path_set);
+ if (!hw_path_mode)
+ return false;
+
+ if (!dal_scaler_adj_group_apply_scaling(
+ param,
+ container,
+ reason,
+ hw_path_mode))
+ return false;
+ dal_ds_dispatch_setup_info_frame(ds, path_mode, hw_path_mode);
+ dal_memset(&hw_underscan_adj,
+ 0,
+ sizeof(struct hw_underscan_adjustment));
+ /* no need call it build_deflicker_adjustment */
+ hw_underscan_adj.hw_overscan = hw_path_mode->mode.overscan;
+ /*just create struct hw_underscan_adjustment_data is enough to use,
+ * no need a HWAdjustment */
+ (*hw_underscan_data)->hw_adj_id = HW_ADJUSTMENT_ID_OVERSCAN;
+ (*hw_underscan_data)->hw_underscan_adj = hw_underscan_adj;
+ return true;
+}
+
+static enum ds_return set_underscan_adjustment(
+ struct ds_dispatch *ds,
+ struct display_path *display_path,
+ enum adjustment_id adjust_id,
+ int32_t value,
+ const struct path_mode *path_mode,
+ struct adj_container *container)
+{
+ enum ds_return result = DS_ERROR;
+ struct hw_path_mode_set *hw_path_set = NULL;
+ struct ds_adjustment_scaler scaler;
+ struct hw_underscan_adjustment_data data = { 0 };
+ struct hw_underscan_adjustment_data *hw_underscan_data = &data;
+
+ hw_path_set = dal_hw_path_mode_set_create();
+ if (!hw_path_set)
+ return DS_ERROR;
+
+ if (!dal_scaler_adj_group_build_scaler_parameter(
+ path_mode,
+ container,
+ BUILD_PATH_SET_REASON_SET_ADJUSTMENT,
+ adjust_id,
+ value,
+ NULL,
+ display_path,
+ &scaler)) {
+ result = DS_ERROR;
+ goto fail;
+ }
+
+ if (!prepare_underscan(
+ ds,
+ path_mode,
+ &scaler,
+ container,
+ display_path,
+ &hw_underscan_data,
+ hw_path_set)) {
+ result = DS_ERROR;
+ goto fail;
+ }
+
+ if (dal_hw_sequencer_set_overscan_adj(
+ ds->hwss,
+ hw_path_set,
+ hw_underscan_data) == HWSS_RESULT_OK)
+ result = DS_SUCCESS;
+ else if (dal_adj_info_set_update_cur_value(
+ &container->adj_info_set,
+ adjust_id,
+ value))
+ result = DS_SUCCESS;
+ else
+ result = DS_ERROR;
+fail:
+ dal_hw_path_mode_set_destroy(&hw_path_set);
+ return result;
+}
+
+enum ds_return dal_scaler_adj_group_set_adjustment(
+ struct ds_dispatch *ds,
+ const uint32_t display_index,
+ struct display_path *display_path,
+ enum adjustment_id adjust_id,
+ int32_t value)
+{
+ struct adj_container *container;
+ struct path_mode_set_with_data *pms_wd;
+ const struct path_mode *path_mode;
+ enum ds_return result = DS_ERROR;
+ const struct adjustment_info *adj_info;
+
+ pms_wd = dal_ds_dispatch_get_active_pms_with_data(ds);
+ if (NULL == pms_wd)
+ return DS_ERROR;
+ container = dal_ds_dispatch_get_adj_container_for_path(
+ ds, display_index);
+ if (NULL == container)
+ return DS_ERROR;
+
+ path_mode =
+ dal_pms_with_data_get_path_mode_for_display_index(
+ pms_wd,
+ display_index);
+
+ if (NULL == path_mode)
+ return DS_ERROR;
+
+ adj_info = dal_adj_info_set_get_adj_info(
+ &container->adj_info_set,
+ adjust_id);
+ if (NULL == adj_info)
+ return DS_ERROR;
+
+ if (adj_info->adj_data.ranged.cur == value) {
+ if (dal_adj_container_is_adjustment_committed(
+ container,
+ adjust_id))
+ /* we have set the same adjustment, do nothing, bypass
+ */
+ return DS_SUCCESS;
+ else if (ADJ_ID_UNDERSCAN == adjust_id) {
+ if (value == adj_info->adj_data.ranged.def &&
+ value == adj_info->adj_data.ranged.def) {
+ /* this is the initial call since our setmode's
+ * default: no underscan. We don't need any 0
+ * underscan adjustment after setmode. only set
+ * committed.
+ */
+ dal_adj_container_commit_adj(
+ container,
+ adjust_id);
+ return DS_SUCCESS;
+ }
+ }
+ }
+
+ if (adj_info->adj_data.ranged.max < value ||
+ adj_info->adj_data.ranged.min > value)
+ return DS_ERROR;
+ if (!dal_adj_info_set_update_cur_value(
+ &container->adj_info_set,
+ adjust_id,
+ value))
+ return DS_ERROR;
+ if (adjust_id == ADJ_ID_UNDERSCAN || adjust_id == ADJ_ID_UNDERSCAN_TYPE)
+ result = set_underscan_adjustment(
+ ds,
+ display_path,
+ adjust_id,
+ value,
+ path_mode,
+ container);
+ else {
+ dal_logger_write(ds->dal_context->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "adj_id isn't for scaler_adj_group");
+ return DS_ERROR;
+ }
+ if (result != DS_ERROR)
+ dal_adj_container_commit_adj(container, adjust_id);
+
+ return result;
+}
diff --git a/drivers/gpu/drm/amd/dal/display_service/scaler_adj_group.h b/drivers/gpu/drm/amd/dal/display_service/scaler_adj_group.h
new file mode 100644
index 000000000000..27819a896b4f
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/scaler_adj_group.h
@@ -0,0 +1,57 @@
+/*
+ * 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_SCALER_ADJ_GROUP_H__
+#define __DAL_SCALER_ADJ_GROUP_H__
+
+#include "include/adjustment_types.h"
+#include "ds_dispatch.h"
+
+struct ds_adjustment_scaler;
+
+enum ds_return dal_scaler_adj_group_set_adjustment(
+ struct ds_dispatch *ds,
+ const uint32_t display_index,
+ struct display_path *display_path,
+ enum adjustment_id adjust_id,
+ int32_t value);
+
+bool dal_scaler_adj_group_apply_scaling(
+ const struct ds_adjustment_scaler *param,
+ struct adj_container *container,
+ enum build_path_set_reason reason,
+ struct hw_path_mode *hw_path_mode);
+
+bool dal_scaler_adj_group_build_scaler_parameter(
+ const struct path_mode *path_mode,
+ struct adj_container *container,
+ enum build_path_set_reason reason,
+ enum adjustment_id adjust_id,
+ int32_t value,
+ const struct ds_underscan_desc *underscan_desc,
+ const struct display_path *display_path,
+ struct ds_adjustment_scaler *param);
+
+#endif /* __DAL_SCALER_ADJ_GROUP_H__ */
diff --git a/drivers/gpu/drm/amd/dal/display_service/set_mode_params.c b/drivers/gpu/drm/amd/dal/display_service/set_mode_params.c
new file mode 100644
index 000000000000..e49ef22a6c9b
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/set_mode_params.c
@@ -0,0 +1,822 @@
+/*
+ * 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/set_mode_interface.h"
+#include "include/topology_mgr_interface.h"
+#include "include/dcs_interface.h"
+
+#include "include/hw_path_mode_set_interface.h"
+#include "include/display_path_set_interface.h"
+#include "include/link_service_interface.h"
+#include "include/logger_interface.h"
+
+#include "ds_translation.h"
+
+struct hw_path_mode_set_map {
+ uint32_t display_index;
+ uint32_t offset_in_hw_path_mode_set;
+ enum scaling_transformation scl_trans;
+};
+
+struct set_mode_params {
+ struct display_path_set *display_path_set;
+ struct hw_path_mode_set *hw_path_mode_set;
+ struct hw_path_mode_set *hw_path_mode_set_for_guaranteed;
+ struct hw_path_mode_set_map map[MAX_COFUNCTIONAL_PATHS];
+ struct topology_mgr *tm;
+ struct hw_sequencer *hws;
+ struct dal_context *ctx;
+ uint32_t path_num;
+ uint32_t guaranteed_validation_count;
+};
+
+static struct hw_path_mode *get_hw_path_mode_by_display_index(
+ struct set_mode_params *smp,
+ uint32_t display_index)
+{
+ uint32_t i;
+
+ for (i = 0; i < smp->path_num; i++)
+ if (smp->map[i].display_index == display_index)
+ return dal_hw_path_mode_set_get_path_by_index(
+ smp->hw_path_mode_set,
+ smp->map[i].offset_in_hw_path_mode_set);
+
+ return NULL;
+}
+
+bool dal_set_mode_params_update_view_on_path(
+ struct set_mode_params *smp,
+ uint32_t display_index,
+ const struct view *vw)
+{
+ struct hw_path_mode *path_mode =
+ get_hw_path_mode_by_display_index(smp, display_index);
+
+ if (path_mode && vw) {
+ path_mode->mode.view.height = vw->height;
+ path_mode->mode.view.width = vw->width;
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * dal_set_mode_params_validate_stereo_3d_format
+ *
+ * Validates Stereo Format in logical layer
+ *
+ */
+bool dal_set_mode_params_validate_stereo_3d_format(
+ struct set_mode_params *smp,
+ struct display_path *display_path,
+ const struct crtc_timing *timing,
+ enum view_3d_format view_3d_format)
+{
+ enum timing_3d_format timing3DFormat =
+ dal_ds_translation_get_active_timing_3d_format(
+ timing->timing_3d_format,
+ view_3d_format);
+ enum signal_type signal =
+ dal_display_path_get_query_signal(
+ display_path,
+ SINK_LINK_INDEX);
+
+ switch (timing3DFormat) {
+ case TIMING_3D_FORMAT_HW_FRAME_PACKING:
+ case TIMING_3D_FORMAT_SW_FRAME_PACKING:
+ /* Frame Packing defined only by DP and HDMI specs */
+ if (!dal_is_dp_signal(signal) && !dal_is_hdmi_signal(signal))
+ return false;
+ break;
+
+ case TIMING_3D_FORMAT_SBS_SW_PACKED:
+ case TIMING_3D_FORMAT_TB_SW_PACKED:
+ /* Driver supports only HDMI signaling for these formats */
+ if (!dal_is_hdmi_signal(signal))
+ return false;
+
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+bool dal_set_mode_params_update_mode_timing_on_path(
+ struct set_mode_params *smp,
+ uint32_t display_index,
+ const struct mode_timing *mode_timing,
+ enum view_3d_format format)
+{
+ struct hw_path_mode *path_mode =
+ get_hw_path_mode_by_display_index(smp, display_index);
+ struct display_path *display_path =
+ dal_display_path_set_index_to_path(
+ smp->display_path_set, display_index);
+ enum signal_type asic_signal =
+ dal_display_path_get_query_signal(
+ display_path,
+ ASIC_LINK_INDEX);
+
+ if (path_mode == NULL || mode_timing == NULL)
+ return false;
+
+ dal_ds_translation_patch_hw_view_for_3d(
+ &path_mode->mode.view,
+ &mode_timing->crtc_timing,
+ format);
+ dal_ds_translation_hw_crtc_timing_from_crtc_timing(
+ &path_mode->mode.timing,
+ &mode_timing->crtc_timing,
+ format,
+ asic_signal);
+ dal_ds_translation_setup_hw_stereo_mixer_params(
+ &path_mode->mode,
+ &mode_timing->crtc_timing,
+ format);
+
+ path_mode->mode.refresh_rate = mode_timing->mode_info.field_rate;
+
+ return dal_set_mode_params_validate_stereo_3d_format(
+ smp,
+ display_path,
+ &mode_timing->crtc_timing,
+ format);
+}
+
+bool dal_set_mode_params_update_scaling_on_path(
+ struct set_mode_params *smp,
+ uint32_t display_index,
+ enum scaling_transformation st)
+{
+ uint32_t i;
+ /*
+ * we can only compute the scalar src/dst here if we are guaranteed
+ * there is no update call on View or Timing on this path later.
+ * Since that's not possible, cache the scalingTrans, and translate just
+ * before we call HWSS
+ */
+ for (i = 0; i < smp->path_num; ++i)
+ if (smp->map[i].display_index == display_index) {
+ smp->map[i].scl_trans = st;
+ return true;
+ }
+
+ return false;
+}
+
+bool dal_set_mode_params_update_pixel_format_on_path(
+ struct set_mode_params *smp,
+ uint32_t display_index,
+ enum pixel_format pf)
+{
+ struct hw_path_mode *path_mode =
+ get_hw_path_mode_by_display_index(smp, display_index);
+
+ if (path_mode) {
+ path_mode->mode.pixel_format = pf;
+ return true;
+ } else
+ return false;
+}
+
+bool dal_set_mode_params_update_tiling_mode_on_path(
+ struct set_mode_params *smp,
+ uint32_t display_index,
+ enum tiling_mode tm)
+{
+ struct hw_path_mode *path_mode =
+ get_hw_path_mode_by_display_index(smp, display_index);
+
+ if (path_mode) {
+ path_mode->mode.tiling_mode = tm;
+ return true;
+ } else
+ return false;
+}
+
+static void update_hw_path_mode_scaling_info(struct set_mode_params *smp)
+{
+ uint32_t i;
+
+ for (i = 0; i < smp->path_num; ++i) {
+ struct hw_path_mode *path_mode =
+ dal_hw_path_mode_set_get_path_by_index(
+ smp->hw_path_mode_set,
+ smp->map[i].offset_in_hw_path_mode_set);
+
+ struct view src = path_mode->mode.view;
+ struct view dst = { path_mode->mode.timing.h_addressable,
+ path_mode->mode.timing.v_addressable };
+
+ path_mode->mode.scaling_info.dst = dst;
+ path_mode->mode.scaling_info.src = src;
+ path_mode->mode.scaling_info.signal =
+ dal_display_path_get_config_signal(
+ path_mode->display_path, SINK_LINK_INDEX);
+
+ switch (smp->map[i].scl_trans) {
+ case SCALING_TRANSFORMATION_IDENTITY:
+ case SCALING_TRANSFORMATION_CENTER_TIMING:
+ path_mode->mode.scaling_info.dst = path_mode->mode.view;
+ break;
+ case SCALING_TRANSFORMATION_FULL_SCREEN_SCALE:
+ path_mode->mode.scaling_info.dst.width =
+ path_mode->mode.timing.h_addressable;
+ path_mode->mode.scaling_info.dst.height =
+ path_mode->mode.timing.v_addressable;
+ break;
+ case SCALING_TRANSFORMATION_PRESERVE_ASPECT_RATIO_SCALE:
+ if (src.width * dst.height <
+ dst.width * src.height) {
+ /* dst is wider in aspect ratio,
+ * shrinking pDest->pixelWidth */
+ path_mode->mode.scaling_info.dst.width =
+ (dst.height * src.width) /
+ src.height;
+ } else {
+ if (src.width * 100 / src.height !=
+ dst.width * 100 /
+ dst.height) {
+ /* note: here we will get 1600x900 which
+ * is using 1776x1000 as based mode, but
+ * gets 1776x999 as requested
+ * destination. 1776/1000 = 1.776,
+ * 1600/900 = 1.777, we
+ * should treat these two are in same
+ * ratio.
+ */
+ path_mode->mode.scaling_info.dst.
+ height = (dst.width *
+ src.height) /
+ src.width;
+ }
+ }
+ break;
+ default:
+ dal_logger_write(smp->ctx->logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "%s: something is wrong here, why do we have bogus parameters?",
+ __func__);
+ break;
+ }
+ }
+}
+
+#define VALID_VIEWS_NUM 2
+
+static const struct view valid_views[VALID_VIEWS_NUM] = {
+ { 640, 480 },
+ { 800, 600 } };
+
+/*
+ * packed_pixel_validate_path_mode
+ *
+ * Validates Path Mode considering packed pixel format limitations
+ * (only if this path driven in packed pixel format)
+ * Limitations are as following:
+ * 1. No scaling
+ * 2. Supports ARGB8888 pixel format and ARGB2101010 pixel format only
+ * 3. Supports only 3 modes: Native, 640x480 and 800x600.
+ */
+static bool packed_pixel_validate_path_mode(
+ const struct hw_path_mode *path_mode)
+{
+ const struct monitor_patch_info *patch_info;
+
+ if (dal_dcs_get_enabled_packed_pixel_format(
+ dal_display_path_get_dcs(path_mode->display_path)) !=
+ DCS_PACKED_PIXEL_FORMAT_NOT_PACKED) {
+ uint32_t i = 0;
+ /* No scaling (centered/identity only) */
+ if (path_mode->mode.scaling_info.src.width !=
+ path_mode->mode.scaling_info.dst.width ||
+ path_mode->mode.scaling_info.src.height !=
+ path_mode->mode.scaling_info.dst.height)
+ return false;
+
+ /* Verify that the pixel format is a supported one *
+ * Block 8, 16, 64 pixel format, and 32 XRBIAS pixel format,
+ * because OPENGL/D3d does not support them when packed pixel
+ * feature enables */
+ if (path_mode->mode.pixel_format != PIXEL_FORMAT_ARGB8888 &&
+ path_mode->mode.pixel_format !=
+ PIXEL_FORMAT_ARGB2101010)
+ return false;
+
+ /* Allow identity */
+ if (path_mode->mode.timing.h_addressable ==
+ path_mode->mode.view.width &&
+ path_mode->mode.timing.v_addressable ==
+ path_mode->mode.view.height)
+ return true;
+
+ patch_info = dal_dcs_get_monitor_patch_info(
+ dal_display_path_get_dcs(
+ path_mode->display_path),
+ MONITOR_PATCH_TYPE_SINGLE_MODE_PACKED_PIXEL);
+
+ if (patch_info)
+ return false;
+
+ /* Allow predefined views as centered */
+ for (i = 0; i < VALID_VIEWS_NUM; ++i) {
+ if (path_mode->mode.view.width ==
+ valid_views[i].width &&
+ path_mode->mode.view.height ==
+ valid_views[i].height)
+ return true;
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ *
+ *
+ * Validates Path Mode considering wireless display limitations
+ * (only if this path signal type is wireless)
+ * Limitations are as following:
+ * 1. No scaling
+ * 2. Supports YCbCr444 pixel format only
+ *
+ * returns true if this path mode valid, false otherwise
+ */
+static bool wireless_validate_path_mode(const struct hw_path_mode *path_mode)
+{
+ enum signal_type signal =
+ dal_display_path_get_config_signal(
+ path_mode->display_path,
+ SINK_LINK_INDEX);
+
+ /* check if this path is Wireless Display path */
+ if (signal == SIGNAL_TYPE_WIRELESS) {
+ /* VCE can only accept YCbCr444 streams for encoding */
+ if (path_mode->mode.timing.flags.PIXEL_ENCODING !=
+ HW_PIXEL_ENCODING_YCBCR444)
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * validate_path_mode
+ *
+ * Does the following validations on the given path mode:
+ * 1. Packed Pixel Format validation
+ *
+ * returns true if this path mode valid, false otherwise
+ */
+static bool validate_path_mode(
+ struct set_mode_params *smp,
+ const struct hw_path_mode *path_mode,
+ bool guaranteed_validation)
+{
+ /* validate path against packed pixel limitations */
+ bool is_valid_path = packed_pixel_validate_path_mode(path_mode);
+
+ /* validate path against wireless limitations */
+ if (is_valid_path)
+ is_valid_path = wireless_validate_path_mode(path_mode);
+
+ /* validate path against link limitations */
+ if (is_valid_path) {
+ struct display_path *display_path = path_mode->display_path;
+ uint32_t display_index =
+ dal_display_path_get_display_index(display_path);
+ uint32_t link_count =
+ dal_display_path_get_number_of_links(display_path);
+ uint32_t i;
+
+ struct link_validation_flags flags = { 0 };
+
+ flags.CANDIDATE_TIMING = guaranteed_validation;
+ flags.START_OF_VALIDATION =
+ smp->guaranteed_validation_count == 0;
+ flags.DYNAMIC_VALIDATION = 1;
+
+ for (i = 0; i < link_count; ++i) {
+ struct link_service *ls =
+ dal_display_path_get_link_query_interface(
+ display_path, i);
+
+ if (!dal_ls_validate_mode_timing(
+ ls,
+ display_index,
+ &path_mode->mode.timing,
+ flags)) {
+ is_valid_path = false;
+ break;
+ }
+ }
+ }
+
+ return is_valid_path;
+}
+
+static bool validate_path_mode_set(
+ struct set_mode_params *smp,
+ struct hw_path_mode_set *path_set)
+{
+ return dal_hw_sequencer_validate_display_hwpms(smp->hws, path_set) ==
+ HWSS_RESULT_OK;
+}
+
+static void package_hw_pms_for_guaranteed_validation(
+ struct set_mode_params *smp)
+{
+ uint32_t i;
+ uint32_t max_cofunctional_targets =
+ dal_tm_max_num_cofunctional_targets(smp->tm);
+ struct hw_path_mode *path_mode_src =
+ dal_hw_path_mode_set_get_path_by_index(
+ smp->hw_path_mode_set, 0);
+
+ for (i = 0; i < max_cofunctional_targets; ++i) {
+ struct hw_path_mode *path_mode_dst =
+ dal_hw_path_mode_set_get_path_by_index(
+ smp->hw_path_mode_set_for_guaranteed,
+ i);
+ /* copy the 1 path maxCofunctionalPath times */
+ *path_mode_dst = *path_mode_src;
+ }
+}
+
+bool dal_set_mode_params_is_path_mode_set_supported(
+ struct set_mode_params *smp)
+{
+ uint32_t i;
+ uint32_t paths_number = dal_hw_path_mode_set_get_paths_number(
+ smp->hw_path_mode_set);
+ update_hw_path_mode_scaling_info(smp);
+
+ for (i = 0; i < paths_number; ++i) {
+ if (!validate_path_mode(
+ smp,
+ dal_hw_path_mode_set_get_path_by_index(
+ smp->hw_path_mode_set,
+ i),
+ false))
+ return false;
+ }
+
+ return validate_path_mode_set(smp, smp->hw_path_mode_set);
+}
+
+/* return true if the parameters can be set, and is guaranteed regardless other
+ * modes being set on other paths
+ */
+bool dal_set_mode_params_is_path_mode_set_guaranteed(
+ struct set_mode_params *smp)
+{
+ uint32_t display_index;
+ /* guaranteed:
+ *
+ * 1. assuming each path is allocated (guaranteed) {[total available
+ * video memory bandwidth] / [maximum simultaneous enabled display]} to
+ * work with, does the given configuration passes still passes
+ * validation?
+ *
+ * this basically mean if all path are doing guaranteed mode, upper
+ * layer can safely assume the mode is cofunctional without calling HW
+ * to validate if the multiple path modes are cofunctional
+ *
+ * 2. only meaningful for 1 path configuration. We will not guarantee
+ * multiple path mode as this case is not useful
+ * note: to simplify HW layer code, when we are asked to if a path mode
+ * is guaranteed (if SetModeParam contain more than 1 path mode this
+ * method would fail), here we get the max number of cofunctional path
+ * from TM, and duplicate the 1 path mode [max cofunctional path] times
+ * and store in HwPathModeSet, and call HWS to validate
+ */
+
+ if (!smp->hw_path_mode_set_for_guaranteed)
+ return false;
+
+ /* When stereo mixer present, we cannot guarantee this solution due to
+ * exceptional resource arbitration
+ */
+ display_index =
+ dal_display_path_get_display_index(
+ dal_hw_path_mode_set_get_path_by_index(
+ smp->hw_path_mode_set_for_guaranteed, 0)->
+ display_path);
+
+ update_hw_path_mode_scaling_info(smp);
+
+ /* We validate path mode in original set, since guaranteed is not
+ * prepared yet */
+ if (!validate_path_mode(
+ smp,
+ dal_hw_path_mode_set_get_path_by_index(
+ smp->hw_path_mode_set, 0),
+ true))
+ return false;
+
+ smp->guaranteed_validation_count++;
+
+ package_hw_pms_for_guaranteed_validation(smp);
+
+ return validate_path_mode_set(
+ smp,
+ smp->hw_path_mode_set_for_guaranteed);
+}
+
+bool dal_set_mode_params_report_single_selected_timing(
+ struct set_mode_params *smp, uint32_t display_index)
+{
+ struct display_path *display_path =
+ dal_tm_display_index_to_display_path(smp->tm, display_index);
+ if (display_path != NULL &&
+ dal_display_path_get_dcs(display_path) != NULL)
+ return dal_dcs_report_single_selected_timing(
+ dal_display_path_get_dcs(display_path));
+
+ return false;
+}
+
+bool dal_set_mode_params_report_ce_mode_only(struct set_mode_params *smp,
+ uint32_t display_index)
+{
+ struct display_path *display_path =
+ dal_tm_display_index_to_display_path(
+ smp->tm,
+ display_index);
+ struct dcs *dcs = dal_display_path_get_dcs(display_path);
+
+ if (dcs) {
+ enum signal_type signal =
+ dal_display_path_get_query_signal(
+ display_path,
+ SINK_LINK_INDEX);
+ bool is_hdmi = signal == SIGNAL_TYPE_HDMI_TYPE_A;
+ bool enabled = false;
+
+ if (dal_dcs_get_fid9204_allow_ce_mode_only_option(
+ dcs,
+ is_hdmi,
+ &enabled))
+ return enabled;
+ }
+
+ return false;
+}
+
+bool dal_set_mode_params_init_with_topology(
+ struct set_mode_params *smp,
+ const uint32_t display_idx[],
+ uint32_t idx_num)
+{
+ struct hw_path_mode path_mode;
+
+ ASSERT(smp->display_path_set == NULL);
+ ASSERT(smp->hw_path_mode_set == NULL);
+
+ /*
+ * acquire DisplayPath with resource allocated from TM
+ */
+ smp->display_path_set =
+ dal_tm_create_resource_context_for_display_indices(
+ smp->tm,
+ display_idx,
+ idx_num);
+
+ if (smp->display_path_set == NULL) {
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+
+ /*
+ * create hw_path_mode_set for validating Guaranteed configuration if
+ * for signal display path case for multiple display path topology,
+ * guaranteed is not meaningful, thus can always return false when asked
+ * is_path_mode_set_guaranteed(). in this case we don't need to create
+ * the hw_path_mode_set
+ */
+ if (idx_num == 1) {
+
+ smp->hw_path_mode_set_for_guaranteed =
+ dal_hw_path_mode_set_create();
+
+ if (smp->hw_path_mode_set_for_guaranteed) {
+ uint32_t i;
+
+ uint32_t max_cofunctional_targets =
+ dal_tm_max_num_cofunctional_targets(smp->tm);
+
+ for (i = 0; i < max_cofunctional_targets; i++) {
+ dal_memset(&path_mode, 0, sizeof(path_mode));
+ path_mode.display_path =
+ dal_display_path_set_index_to_path(
+ smp->display_path_set,
+ display_idx[0]);
+
+ dal_hw_path_mode_set_add(
+ smp->hw_path_mode_set_for_guaranteed,
+ &path_mode, NULL);
+ }
+ }
+ }
+
+ smp->hw_path_mode_set = dal_hw_path_mode_set_create();
+
+ if (smp->hw_path_mode_set) {
+ uint32_t i;
+
+ for (i = 0; i < idx_num; i++) {
+ dal_memset(&path_mode, 0, sizeof(path_mode));
+
+ path_mode.display_path =
+ dal_display_path_set_index_to_path(
+ smp->display_path_set,
+ display_idx[i]);
+
+ dal_hw_path_mode_set_add(
+ smp->hw_path_mode_set,
+ &path_mode,
+ &smp->map[i].offset_in_hw_path_mode_set);
+
+ smp->map[i].display_index = display_idx[i];
+ }
+ smp->path_num = idx_num;
+
+ return true;
+ } else
+ return false;
+}
+
+struct view_stereo_3d_support dal_set_mode_params_get_stereo_3d_support(
+ struct set_mode_params *smp,
+ uint32_t display_index,
+ enum timing_3d_format timing_3d_format)
+{
+ struct view_stereo_3d_support view_stereo_3d_support = {
+ VIEW_3D_FORMAT_NONE };
+ struct display_path *display_path =
+ dal_tm_display_index_to_display_path(smp->tm, display_index);
+
+ if (display_path && dal_display_path_get_dcs(display_path)) {
+ struct dcs_stereo_3d_features stereo_3d_features =
+ dal_dcs_get_stereo_3d_features(
+ dal_display_path_get_dcs(display_path),
+ timing_3d_format);
+ if (stereo_3d_features.flags.SUPPORTED) {
+ view_stereo_3d_support.features.CLONE_MODE =
+ stereo_3d_features.flags.CLONE_MODE;
+ view_stereo_3d_support.features.SCALING =
+ stereo_3d_features.flags.SCALING;
+ view_stereo_3d_support.features.SINGLE_FRAME_SW_PACKED =
+ stereo_3d_features.flags.SINGLE_FRAME_SW_PACKED;
+ view_stereo_3d_support.format =
+ dal_ds_translation_3d_format_timing_to_view(
+ timing_3d_format);
+ }
+ }
+
+ return view_stereo_3d_support;
+}
+
+/* return true if the parameters can be set, and is guaranteed regardless other
+ * modes being set on other paths */
+bool dal_set_mode_params_is_multiple_pixel_encoding_supported(
+ struct set_mode_params *smp,
+ uint32_t display_index)
+{
+ struct hw_path_mode *path_mode =
+ get_hw_path_mode_by_display_index(smp, display_index);
+
+ if (path_mode != NULL && path_mode->display_path != NULL) {
+ enum signal_type signal =
+ dal_display_path_get_config_signal(
+ path_mode->display_path,
+ SINK_LINK_INDEX);
+ switch (signal) {
+ case SIGNAL_TYPE_HDMI_TYPE_A:
+ case SIGNAL_TYPE_WIRELESS:
+ return true;
+ default:
+ return false;
+
+ }
+ }
+ return false;
+}
+
+enum pixel_encoding dal_set_mode_params_get_default_pixel_format_preference(
+ struct set_mode_params *smp,
+ uint32_t display_index)
+{
+ enum pixel_encoding pf = PIXEL_ENCODING_UNDEFINED;
+
+ struct display_path *display_path =
+ dal_tm_display_index_to_display_path(
+ smp->tm,
+ display_index);
+ struct dcs *dcs = dal_display_path_get_dcs(display_path);
+
+ if (dcs) {
+ enum signal_type signal =
+ dal_display_path_get_query_signal(
+ display_path,
+ SINK_LINK_INDEX);
+ bool is_hdmi = signal == SIGNAL_TYPE_HDMI_TYPE_A;
+ bool enabled = false;
+
+ if (dal_dcs_get_fid9204_allow_ce_mode_only_option(
+ dcs, is_hdmi, &enabled))
+ pf = PIXEL_ENCODING_RGB;
+ }
+
+ return pf;
+}
+
+static bool construct(
+ struct set_mode_params *smp,
+ struct set_mode_params_init_data *init_data)
+{
+ if (!init_data->hws)
+ return false;
+ if (!init_data->tm)
+ return false;
+
+ smp->ctx = init_data->ctx;
+ smp->hws = init_data->hws;
+ smp->tm = init_data->tm;
+ return true;
+}
+
+struct set_mode_params *dal_set_mode_params_create(
+ struct set_mode_params_init_data *init_data)
+{
+ struct set_mode_params *smp = dal_alloc(sizeof(struct set_mode_params));
+
+ if (!smp) {
+ BREAK_TO_DEBUGGER();
+ return NULL;
+ }
+
+ if (construct(smp, init_data))
+ return smp;
+
+ BREAK_TO_DEBUGGER();
+ dal_free(smp);
+
+ return NULL;
+}
+
+static void destruct(struct set_mode_params *smp)
+{
+ if (smp->display_path_set)
+ dal_display_path_set_destroy(&smp->display_path_set);
+
+ if (smp->hw_path_mode_set)
+ dal_hw_path_mode_set_destroy(&smp->hw_path_mode_set);
+
+ if (smp->hw_path_mode_set_for_guaranteed)
+ dal_hw_path_mode_set_destroy(
+ &smp->hw_path_mode_set_for_guaranteed);
+}
+
+void dal_set_mode_params_destroy(
+ struct set_mode_params **smp)
+{
+ if (smp == NULL || *smp == NULL)
+ return;
+
+ destruct(*smp);
+
+ dal_free(*smp);
+ *smp = NULL;
+}
diff --git a/drivers/gpu/drm/amd/dal/display_service/single_adj_group.c b/drivers/gpu/drm/amd/dal/display_service/single_adj_group.c
new file mode 100644
index 000000000000..03c9c7886d71
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/single_adj_group.c
@@ -0,0 +1,447 @@
+/*
+ * 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/dcs_interface.h"
+#include "include/signal_types.h"
+#include "include/topology_mgr_interface.h"
+#include "include/adjustment_interface.h"
+#include "include/display_service_types.h"
+#include "include/hw_adjustment_types.h"
+#include "include/hw_sequencer_interface.h"
+#include "include/set_mode_interface.h"
+#include "include/logger_interface.h"
+#include "include/hw_adjustment_set.h"
+
+#include "ds_dispatch.h"
+#include "adjustment_container.h"
+#include "single_adj_group.h"
+
+static void translate_to_hw_dither(
+ uint32_t value,
+ enum pixel_encoding pixel_encoding,
+ union hw_adjustment_bit_depth_reduction *bit_depth)
+{
+ /* truncation */
+ if (DS_BIT_DEPTH_REDUCTION_TRUN6 == value) {
+ bit_depth->bits.TRUNCATE_ENABLED = 1;
+ bit_depth->bits.TRUNCATE_DEPTH = 0;
+ } else if (DS_BIT_DEPTH_REDUCTION_TRUN8 == value ||
+ DS_BIT_DEPTH_REDUCTION_TRUN8_DITH6 == value ||
+ DS_BIT_DEPTH_REDUCTION_TRUN8_FM6 == value) {
+ bit_depth->bits.TRUNCATE_ENABLED = 1;
+ bit_depth->bits.TRUNCATE_DEPTH = 1;
+ } else if (DS_BIT_DEPTH_REDUCTION_TRUN10 == value ||
+ DS_BIT_DEPTH_REDUCTION_TRUN10_DITH6 == value ||
+ DS_BIT_DEPTH_REDUCTION_TRUN10_DITH8 == value ||
+ DS_BIT_DEPTH_REDUCTION_TRUN10_FM8 == value ||
+ DS_BIT_DEPTH_REDUCTION_TRUN10_FM6 == value ||
+ DS_BIT_DEPTH_REDUCTION_TRUN10_DITH8_FM6 == value) {
+ bit_depth->bits.TRUNCATE_ENABLED = 1;
+ bit_depth->bits.TRUNCATE_DEPTH = 2;
+ }
+
+ if (DS_BIT_DEPTH_REDUCTION_DITH6 == value ||
+ DS_BIT_DEPTH_REDUCTION_DITH6_NO_FRAME_RAND == value ||
+ DS_BIT_DEPTH_REDUCTION_FM6 == value) {
+ bit_depth->bits.TRUNCATE_ENABLED = 1;
+ bit_depth->bits.TRUNCATE_DEPTH = 2;
+ bit_depth->bits.TRUNCATE_MODE = 1;
+ }
+
+ /* spatial dither */
+ if (DS_BIT_DEPTH_REDUCTION_DITH6 == value ||
+ DS_BIT_DEPTH_REDUCTION_DITH6_NO_FRAME_RAND == value ||
+ DS_BIT_DEPTH_REDUCTION_TRUN10_DITH6 == value ||
+ DS_BIT_DEPTH_REDUCTION_TRUN8_DITH6 == value) {
+ bit_depth->bits.SPATIAL_DITHER_ENABLED = 1;
+ bit_depth->bits.SPATIAL_DITHER_DEPTH = 0;
+ bit_depth->bits.HIGHPASS_RANDOM = 1;
+ bit_depth->bits.RGB_RANDOM =
+ (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
+ } else if (DS_BIT_DEPTH_REDUCTION_DITH8 == value ||
+ DS_BIT_DEPTH_REDUCTION_DITH8_NO_FRAME_RAND == value ||
+ DS_BIT_DEPTH_REDUCTION_TRUN8_FM6 == value ||
+ DS_BIT_DEPTH_REDUCTION_TRUN10_DITH8 == value ||
+ DS_BIT_DEPTH_REDUCTION_TRUN10_DITH8_FM6 == value) {
+ bit_depth->bits.SPATIAL_DITHER_ENABLED = 1;
+ bit_depth->bits.SPATIAL_DITHER_DEPTH = 1;
+ bit_depth->bits.HIGHPASS_RANDOM = 1;
+ bit_depth->bits.RGB_RANDOM =
+ (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
+ } else if (DS_BIT_DEPTH_REDUCTION_DITH10 == value ||
+ DS_BIT_DEPTH_REDUCTION_DITH10_NO_FRAME_RAND == value ||
+ DS_BIT_DEPTH_REDUCTION_TRUN10_FM8 == value ||
+ DS_BIT_DEPTH_REDUCTION_TRUN10_FM6 == value) {
+ bit_depth->bits.SPATIAL_DITHER_ENABLED = 1;
+ bit_depth->bits.SPATIAL_DITHER_DEPTH = 2;
+ bit_depth->bits.HIGHPASS_RANDOM = 1;
+ bit_depth->bits.RGB_RANDOM =
+ (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
+ }
+
+ if (DS_BIT_DEPTH_REDUCTION_DITH6_NO_FRAME_RAND == value ||
+ DS_BIT_DEPTH_REDUCTION_DITH8_NO_FRAME_RAND == value ||
+ DS_BIT_DEPTH_REDUCTION_DITH10_NO_FRAME_RAND == value) {
+ bit_depth->bits.FRAME_RANDOM = 0;
+ } else
+ bit_depth->bits.FRAME_RANDOM = 1;
+
+ /* temporal dither */
+ if (DS_BIT_DEPTH_REDUCTION_FM6 == value ||
+ DS_BIT_DEPTH_REDUCTION_DITH8_FM6 == value ||
+ DS_BIT_DEPTH_REDUCTION_DITH10_FM6 == value ||
+ DS_BIT_DEPTH_REDUCTION_TRUN10_FM6 == value ||
+ DS_BIT_DEPTH_REDUCTION_TRUN8_FM6 == value ||
+ DS_BIT_DEPTH_REDUCTION_TRUN10_DITH8_FM6 == value) {
+ bit_depth->bits.FRAME_MODULATION_ENABLED = 1;
+ bit_depth->bits.FRAME_MODULATION_DEPTH = 0;
+ } else if (DS_BIT_DEPTH_REDUCTION_FM8 == value ||
+ DS_BIT_DEPTH_REDUCTION_DITH10_FM8 == value ||
+ DS_BIT_DEPTH_REDUCTION_TRUN10_FM8 == value) {
+ bit_depth->bits.FRAME_MODULATION_ENABLED = 1;
+ bit_depth->bits.FRAME_MODULATION_DEPTH = 1;
+ } else if (DS_BIT_DEPTH_REDUCTION_FM10 == value) {
+ bit_depth->bits.FRAME_MODULATION_ENABLED = 1;
+ bit_depth->bits.FRAME_MODULATION_DEPTH = 2;
+ }
+
+}
+enum ds_return dal_single_adj_group_set_adjustment(
+ struct single_adj_group *single_adj,
+ struct display_path *disp_path,
+ enum adjustment_id adj_id,
+ uint32_t value)
+{
+ enum ds_return result = DS_ERROR;
+ enum hwss_result ret = HWSS_RESULT_ERROR;
+ union hw_adjustment_bit_depth_reduction adj_bit_depth = {0};
+ uint32_t display_index = dal_tm_display_path_to_display_index(
+ single_adj->tm,
+ disp_path);
+ struct adj_container *adj_container =
+ dal_ds_dispatch_get_adj_container_for_path(
+ single_adj->ds,
+ display_index);
+ const struct adjustment_info *adj_info =
+ dal_adj_info_set_get_adj_info(
+ &adj_container->adj_info_set, adj_id);
+
+ if (!adj_container)
+ return result;
+
+ if (!adj_info)
+ return result;
+
+ if (adj_info->adj_data_type == ADJ_RANGED) {
+ if (value < adj_info->adj_data.ranged.min ||
+ value > adj_info->adj_data.ranged.max)
+ return result;
+ }
+ if (adj_id == ADJ_ID_BIT_DEPTH_REDUCTION) {
+ if (dal_display_path_is_psr_supported(disp_path) ||
+ !dal_single_adj_group_verify_bit_depth_reduction(
+ single_adj,
+ disp_path,
+ value)) {
+ dal_logger_write(single_adj->dal_context->logger,
+ LOG_MAJOR_DCP,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "Dithering setting %d could not be applied\n",
+ value);
+ return result;
+ }
+ }
+ if (!dal_adj_info_set_update_cur_value(
+ &adj_container->adj_info_set, adj_id, value))
+ return result;
+
+ if (!dal_single_adj_group_setup_bit_depth_parameters(
+ single_adj,
+ disp_path,
+ value,
+ &adj_bit_depth))
+ return result;
+
+ ret = dal_hw_sequencer_set_bit_depth_reduction_adj(
+ single_adj->hws,
+ disp_path,
+ &adj_bit_depth);
+
+ if (ret == HWSS_RESULT_OK)
+ result = DS_SUCCESS;
+
+ if (result == DS_SUCCESS)
+ dal_adj_container_commit_adj(adj_container, adj_id);
+
+ return result;
+}
+
+bool dal_single_adj_group_verify_bit_depth_reduction(
+ struct single_adj_group *single_adj,
+ struct display_path *disp_path,
+ uint32_t value)
+{
+ enum color_depth_index color_depth;
+ uint32_t display_index = dal_tm_display_path_to_display_index(
+ single_adj->tm,
+ disp_path);
+ const struct path_mode *path_mode =
+ dal_pms_with_data_get_path_mode_for_display_index(
+ single_adj->ds->set, display_index);
+
+ if (value < 0 || value > DS_BIT_DEPTH_REDUCTION_MAX)
+ return false;
+
+ if (value == DS_BIT_DEPTH_REDUCTION_DISABLE ||
+ value == DS_BIT_DEPTH_REDUCTION_DRIVER_DEFAULT)
+ return true;
+
+ if (path_mode == NULL || path_mode->mode_timing == NULL)
+ return false;
+
+ color_depth =
+ path_mode->mode_timing->crtc_timing.display_color_depth;
+ if (color_depth == COLOR_DEPTH_INDEX_888) {
+ if (value == DS_BIT_DEPTH_REDUCTION_DITH8 ||
+ value == DS_BIT_DEPTH_REDUCTION_DITH8_NO_FRAME_RAND ||
+ value == DS_BIT_DEPTH_REDUCTION_FM8 ||
+ value == DS_BIT_DEPTH_REDUCTION_TRUN8 ||
+ value == DS_BIT_DEPTH_REDUCTION_DITH10_FM8 ||
+ value == DS_BIT_DEPTH_REDUCTION_TRUN10_DITH8 ||
+ value == DS_BIT_DEPTH_REDUCTION_TRUN10_FM8)
+ return true;
+ } else if (color_depth == COLOR_DEPTH_INDEX_666) {
+ if (value == DS_BIT_DEPTH_REDUCTION_DITH6 ||
+ value == DS_BIT_DEPTH_REDUCTION_DITH6_NO_FRAME_RAND ||
+ value == DS_BIT_DEPTH_REDUCTION_FM6 ||
+ value == DS_BIT_DEPTH_REDUCTION_TRUN6 ||
+ value == DS_BIT_DEPTH_REDUCTION_DITH10_FM6 ||
+ value == DS_BIT_DEPTH_REDUCTION_TRUN10_DITH6 ||
+ value == DS_BIT_DEPTH_REDUCTION_TRUN10_FM6 ||
+ value == DS_BIT_DEPTH_REDUCTION_DITH8_FM6 ||
+ value == DS_BIT_DEPTH_REDUCTION_TRUN8_DITH6 ||
+ value == DS_BIT_DEPTH_REDUCTION_TRUN8_FM6 ||
+ value == DS_BIT_DEPTH_REDUCTION_TRUN10_DITH8_FM6)
+ return true;
+ } else if (color_depth == COLOR_DEPTH_INDEX_101010) {
+ if (value == DS_BIT_DEPTH_REDUCTION_DITH10 ||
+ value == DS_BIT_DEPTH_REDUCTION_DITH10_NO_FRAME_RAND ||
+ value == DS_BIT_DEPTH_REDUCTION_FM10 ||
+ value == DS_BIT_DEPTH_REDUCTION_TRUN10)
+ return true;
+ }
+ return false;
+}
+
+bool dal_single_adj_group_setup_bit_depth_parameters(
+ struct single_adj_group *single_adj,
+ struct display_path *disp_path,
+ uint32_t value,
+ union hw_adjustment_bit_depth_reduction *bit_depth)
+{
+ bool ret = true;
+ enum display_color_depth color_depth;
+ enum pixel_encoding pixel_encoding;
+ uint32_t display_index = dal_tm_display_path_to_display_index(
+ single_adj->tm,
+ disp_path);
+ const struct path_mode *path_mode =
+ dal_pms_with_data_get_path_mode_for_display_index(
+ single_adj->ds->set, display_index);
+
+ if (path_mode == NULL || path_mode->mode_timing == NULL)
+ return false;
+
+ color_depth =
+ path_mode->mode_timing->crtc_timing.display_color_depth;
+ pixel_encoding =
+ path_mode->mode_timing->crtc_timing.pixel_encoding;
+
+ /* Disable diethering if FEATURE_PIXEL_PERFECT_OUTPUT
+ * is set and the display color depth matches the
+ * surface pixel format (only applies to 8-bit) */
+ if (dal_adapter_service_is_feature_supported(
+ FEATURE_PIXEL_PERFECT_OUTPUT) &&
+ color_depth == DISPLAY_COLOR_DEPTH_888 &&
+ path_mode->pixel_format == PIXEL_FORMAT_ARGB8888)
+ return true;
+
+ if (value == DS_BIT_DEPTH_REDUCTION_DRIVER_DEFAULT) {
+ if (color_depth == DISPLAY_COLOR_DEPTH_666)
+ bit_depth->bits.SPATIAL_DITHER_DEPTH = 0;
+ else if (color_depth == DISPLAY_COLOR_DEPTH_888)
+ bit_depth->bits.SPATIAL_DITHER_DEPTH = 1;
+ else if (color_depth == DISPLAY_COLOR_DEPTH_101010 ||
+ color_depth == DISPLAY_COLOR_DEPTH_121212)
+ return true;
+ else
+ return false;
+ bit_depth->bits.SPATIAL_DITHER_ENABLED = 1;
+ bit_depth->bits.FRAME_RANDOM = 1;
+ bit_depth->bits.RGB_RANDOM =
+ (pixel_encoding == PIXEL_ENCODING_RGB) ? 1 : 0;
+ return true;
+ }
+ translate_to_hw_dither(value, pixel_encoding, bit_depth);
+
+ if (bit_depth->bits.FRAME_MODULATION_ENABLED == 1) {
+ switch (dal_display_path_get_config_signal(
+ disp_path, SINK_LINK_INDEX)) {
+ {
+ case SIGNAL_TYPE_RGB:
+ case SIGNAL_TYPE_DVI_SINGLE_LINK:
+ case SIGNAL_TYPE_DVI_SINGLE_LINK1:
+ case SIGNAL_TYPE_DVI_DUAL_LINK:
+ case SIGNAL_TYPE_HDMI_TYPE_A:
+ case SIGNAL_TYPE_DISPLAY_PORT:
+ case SIGNAL_TYPE_DISPLAY_PORT_MST:
+ bit_depth->bits.TEMPORAL_LEVEL = 0;
+ }
+ break;
+ case SIGNAL_TYPE_LVDS:
+ case SIGNAL_TYPE_EDP:
+ {
+ union panel_misc_info panel_info;
+ struct dcs *dcs = dal_display_path_get_dcs(disp_path);
+
+ bit_depth->bits.TEMPORAL_LEVEL = 0;
+ if (dal_dcs_get_panel_misc_info(dcs, &panel_info)) {
+ if (panel_info.bits.GREY_LEVEL)
+ bit_depth->bits.TEMPORAL_LEVEL = 1;
+ }
+ }
+ break;
+ default:
+ ret = false;
+ break;
+ }
+ bit_depth->bits.FRC_25 = 0;
+ bit_depth->bits.FRC_50 = 0;
+ bit_depth->bits.FRC_75 = 0;
+ }
+ return ret;
+}
+
+bool dal_single_adj_group_include_adjustment(
+ struct single_adj_group *single_adj,
+ struct display_path *disp_path,
+ struct ds_adj_id_value adj,
+ struct hw_adjustment_set *set)
+{
+ union hw_adjustment_bit_depth_reduction *bit_depth = NULL;
+ uint32_t display_index = dal_tm_display_path_to_display_index(
+ single_adj->tm, disp_path);
+ struct adj_container *adj_container =
+ dal_ds_dispatch_get_adj_container_for_path(
+ single_adj->ds, display_index);
+ struct adjustment_info *adj_info =
+ dal_adj_info_set_get_adj_info(
+ &adj_container->adj_info_set, adj.adj_id);
+
+ bit_depth = dal_alloc(sizeof(*bit_depth));
+ if (!bit_depth)
+ return false;
+
+ if (adj.adj_id == ADJ_ID_BIT_DEPTH_REDUCTION) {
+ if (dal_display_path_is_psr_supported(disp_path))
+ return false;
+ if (!dal_single_adj_group_verify_bit_depth_reduction(
+ single_adj,
+ disp_path,
+ adj.value)) {
+ adj.value = adj_info->adj_data.ranged.def;
+ dal_adj_info_set_update_cur_value(
+ &adj_container->adj_info_set,
+ adj.adj_id, adj.value);
+ dal_adj_container_commit_adj(
+ adj_container, adj.adj_id);
+ dal_logger_write(single_adj->dal_context->logger,
+ LOG_MAJOR_DCP,
+ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
+ "Dithering setting %d no longer matching color depth ,resetting to default\n",
+ adj.value);
+ }
+ dal_single_adj_group_setup_bit_depth_parameters(
+ single_adj,
+ disp_path,
+ adj.value,
+ bit_depth);
+
+ set->bit_depth = bit_depth;
+
+ } else
+ return false;
+
+ return true;
+}
+
+static bool single_adj_construct(
+ struct single_adj_group *single_adj,
+ struct single_adj_group_init_data *init_data)
+{
+ if (!init_data)
+ return false;
+
+ single_adj->ds = init_data->ds;
+ single_adj->hws = init_data->hws;
+ single_adj->tm = init_data->tm;
+ single_adj->dal_context = init_data->dal_context;
+ return true;
+}
+
+struct single_adj_group *dal_single_adj_group_create(
+ struct single_adj_group_init_data *init_data)
+{
+ struct single_adj_group *single_adj = NULL;
+
+ single_adj = dal_alloc(sizeof(*single_adj));
+
+ if (!single_adj)
+ return NULL;
+
+ if (single_adj_construct(single_adj, init_data))
+ return single_adj;
+
+ dal_free(single_adj);
+
+ return NULL;
+}
+
+static void destruct(
+ struct single_adj_group *single_adj)
+{
+}
+
+void dal_single_adj_group_destroy(
+ struct single_adj_group **single_adj)
+{
+ if (single_adj == NULL || *single_adj == NULL)
+ return;
+ destruct(*single_adj);
+ dal_free(*single_adj);
+ *single_adj = NULL;
+}
diff --git a/drivers/gpu/drm/amd/dal/display_service/single_adj_group.h b/drivers/gpu/drm/amd/dal/display_service/single_adj_group.h
new file mode 100644
index 000000000000..a3761c962a7d
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/display_service/single_adj_group.h
@@ -0,0 +1,75 @@
+/*
+ * 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_SINGLE_ADJ_GROUP_H__
+#define __DAL_SINGLE_ADJ_GROUP_H__
+
+/* Include */
+#include "include/adjustment_types.h"
+
+struct single_adj_group {
+ struct ds_dispatch *ds;
+ struct hw_sequencer *hws;
+ struct topology_mgr *tm;
+ struct dal_context *dal_context;
+};
+
+struct single_adj_group_init_data {
+ struct ds_dispatch *ds;
+ struct hw_sequencer *hws;
+ struct topology_mgr *tm;
+ struct dal_context *dal_context;
+};
+
+struct single_adj_group *dal_single_adj_group_create(
+ struct single_adj_group_init_data *init_data);
+
+void dal_single_adj_group_destroy(
+ struct single_adj_group **single_adj);
+
+bool dal_single_adj_group_include_adjustment(
+ struct single_adj_group *single_adj,
+ struct display_path *disp_path,
+ struct ds_adj_id_value adj,
+ struct hw_adjustment_set *set);
+
+bool dal_single_adj_group_setup_bit_depth_parameters(
+ struct single_adj_group *single_adj,
+ struct display_path *disp_path,
+ uint32_t value,
+ union hw_adjustment_bit_depth_reduction *bit_depth);
+
+bool dal_single_adj_group_verify_bit_depth_reduction(
+ struct single_adj_group *single_adj,
+ struct display_path *disp_path,
+ uint32_t value);
+
+enum ds_return dal_single_adj_group_set_adjustment(
+ struct single_adj_group *single_adj,
+ struct display_path *disp_path,
+ enum adjustment_id adj_id,
+ uint32_t value);
+
+#endif /* __DAL_SINGLE_ADJ_GROUP_H__ */
diff --git a/drivers/gpu/drm/amd/dal/include/adjustment_interface.h b/drivers/gpu/drm/amd/dal/include/adjustment_interface.h
new file mode 100644
index 000000000000..64a9f9f2dd15
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/include/adjustment_interface.h
@@ -0,0 +1,230 @@
+/*
+ * 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_ADJUSTMENT_INTERFACE_H__
+#define __DAL_ADJUSTMENT_INTERFACE_H__
+
+#include "include/display_service_types.h"
+#include "include/adjustment_types.h"
+#include "include/overlay_types.h"
+#include "include/display_path_interface.h"
+
+struct ds_underscan_desc;
+struct adj_container;
+struct info_frame;
+struct ds_dispatch;
+struct hw_adjustment_set;
+struct path_mode;
+struct hw_path_mode;
+
+enum build_path_set_reason;
+
+bool dal_ds_dispatch_is_adjustment_supported(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ enum adjustment_id adjust_id);
+
+enum ds_return dal_ds_dispatch_get_type(
+ struct ds_dispatch *adj,
+ enum adjustment_id adjust_id,
+ enum adjustment_data_type *type);
+
+enum ds_return dal_ds_dispatch_get_property(
+ struct ds_dispatch *adj,
+ uint32_t display_index,
+ enum adjustment_id adjust_id,
+ union adjustment_property *property);
+
+enum ds_return dal_ds_dispatch_set_adjustment(
+ struct ds_dispatch *ds,
+ const uint32_t display_index,
+ enum adjustment_id adjust_id,
+ int32_t value);
+
+enum ds_return dal_ds_dispatch_get_adjustment_current_value(
+ struct ds_dispatch *ds,
+ struct adj_container *container,
+ struct adjustment_info *info,
+ enum adjustment_id id,
+ bool fall_back_to_default);
+
+enum ds_return dal_ds_dispatch_get_adjustment_value(
+ struct ds_dispatch *ds,
+ struct display_path *disp_path,
+ enum adjustment_id adj_id,
+ bool fall_back_to_default,
+ int32_t *value);
+
+const struct raw_gamma_ramp *dal_ds_dispatch_get_current_gamma(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ enum adjustment_id adjust_id);
+
+const struct raw_gamma_ramp *dal_ds_dispatch_get_default_gamma(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ enum adjustment_id adjust_id);
+
+enum ds_return dal_ds_dispatch_set_current_gamma(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ enum adjustment_id adjust_id,
+ const struct raw_gamma_ramp *gamma);
+
+enum ds_return dal_ds_dispatch_set_gamma(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ enum adjustment_id adjust_id,
+ const struct raw_gamma_ramp *gamma);
+
+bool dal_ds_dispatch_get_underscan_info(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ struct ds_underscan_info *info);
+
+bool dal_ds_dispatch_get_underscan_mode(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ struct ds_underscan_desc *desc);
+
+bool dal_ds_dispatch_set_underscan_mode(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ struct ds_underscan_desc *desc);
+
+bool dal_ds_dispatch_setup_overlay(
+ struct ds_dispatch *adj,
+ uint32_t display_index,
+ struct overlay_data *data);
+
+struct adj_container *dal_ds_dispatch_get_adj_container_for_path(
+ const struct ds_dispatch *ds,
+ uint32_t display_index);
+
+void dal_ds_dispatch_set_applicable_adj(
+ struct ds_dispatch *adj,
+ uint32_t display_index,
+ const struct adj_container *applicable);
+
+enum ds_return dal_ds_dispatch_set_color_gamut(
+ struct ds_dispatch *adj,
+ uint32_t display_index,
+ const struct ds_set_gamut_data *data);
+
+enum ds_return dal_ds_dispatch_get_color_gamut(
+ struct ds_dispatch *adj,
+ uint32_t display_index,
+ const struct ds_gamut_reference_data *ref,
+ struct ds_get_gamut_data *data);
+
+enum ds_return dal_ds_dispatch_get_color_gamut_info(
+ struct ds_dispatch *adj,
+ uint32_t display_index,
+ const struct ds_gamut_reference_data *ref,
+ struct ds_gamut_info *data);
+
+enum ds_return dal_ds_dispatch_get_regamma_lut(
+ struct ds_dispatch *adj,
+ uint32_t display_index,
+ struct ds_regamma_lut *data);
+
+enum ds_return dal_ds_dispatch_set_regamma_lut(
+ struct ds_dispatch *adj,
+ uint32_t display_index,
+ struct ds_regamma_lut *data);
+
+enum ds_return dal_ds_dispatch_set_info_packets(
+ struct ds_dispatch *adj,
+ uint32_t display_index,
+ const struct info_frame *info_frames);
+
+enum ds_return dal_ds_dispatch_get_info_packets(
+ struct ds_dispatch *adj,
+ uint32_t display_index,
+ struct info_frame *info_frames);
+
+bool dal_ds_dispatch_initialize_adjustment(struct ds_dispatch *ds);
+
+void dal_ds_dispatch_cleanup_adjustment(struct ds_dispatch *ds);
+
+bool dal_ds_dispatch_build_post_set_mode_adj(
+ struct ds_dispatch *ds,
+ const struct path_mode *mode,
+ struct display_path *display_path,
+ struct hw_adjustment_set *set);
+
+bool dal_ds_dispatch_build_color_control_adj(
+ struct ds_dispatch *ds,
+ const struct path_mode *mode,
+ struct display_path *display_path,
+ struct hw_adjustment_set *set);
+
+bool dal_ds_dispatch_build_include_adj(
+ struct ds_dispatch *ds,
+ const struct path_mode *mode,
+ struct display_path *display_path,
+ struct hw_path_mode *hw_mode,
+ struct hw_adjustment_set *set);
+
+bool dal_ds_dispatch_apply_scaling(
+ struct ds_dispatch *ds,
+ const struct path_mode *mode,
+ struct adj_container *adj_container,
+ enum build_path_set_reason reason,
+ struct hw_path_mode *hw_mode);
+
+void dal_ds_dispatch_update_adj_container_for_path_with_mode_info(
+ struct ds_dispatch *ds,
+ struct display_path *display_path,
+ const struct path_mode *path_mode);
+
+enum ds_return dal_ds_dispatch_get_adjustment_info(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ enum adjustment_id adjust_id,
+ struct adjustment_info *adj_info);
+
+bool dal_ds_dispatch_include_adjustment(
+ struct ds_dispatch *ds,
+ struct display_path *disp_path,
+ struct ds_adj_id_value adj,
+ struct hw_adjustment_set *set);
+
+enum ds_return dal_ds_dispatch_set_gamma_adjustment(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ enum adjustment_id ad_id,
+ const struct raw_gamma_ramp *gamma);
+
+void dal_ds_dispatch_update_adj_container_for_path_with_color_space(
+ struct ds_dispatch *ds,
+ uint32_t display_index,
+ enum ds_color_space color_space);
+
+void dal_ds_dispatch_setup_default_regamma(
+ struct ds_dispatch *ds,
+ struct ds_regamma_lut *regamma);
+
+#endif /* __DAL_ADJUSTMENT_INTERFACE_H__ */
diff --git a/drivers/gpu/drm/amd/dal/include/display_service_interface.h b/drivers/gpu/drm/amd/dal/include/display_service_interface.h
new file mode 100644
index 000000000000..68276babadad
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/include/display_service_interface.h
@@ -0,0 +1,165 @@
+/*
+ * 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 __DISPLAY_SERVICE_INTERFACE_H__
+#define __DISPLAY_SERVICE_INTERFACE_H__
+
+#include "include/display_service_types.h"
+#include "include/display_path_types.h"
+#include "include/grph_object_ctrl_defs.h"
+
+struct display_service;
+struct ds_overlay;
+struct ds_dispatch;
+struct ds_synchronization;
+struct path_mode_set;
+
+struct display_service *dal_display_service_create(
+ struct ds_init_data *data);
+
+void dal_display_service_destroy(
+ struct display_service **ds);
+
+struct ds_dispatch *dal_display_service_get_adjustment_interface(
+ struct display_service *ds);
+
+struct ds_overlay *dal_display_service_get_overlay_interface(
+ struct display_service *ds);
+
+struct ds_dispatch *dal_display_service_get_set_mode_interface(
+ struct display_service *ds);
+
+struct ds_dispatch *dal_display_service_get_reset_mode_interface(
+ struct display_service *ds);
+
+struct ds_synchronization *dal_display_service_get_synchronization_interface(
+ struct display_service *ds);
+
+enum ds_return dal_display_service_notify_v_sync_int_state(
+ struct display_service *ds,
+ uint32_t display_index,
+ bool maintain_v_sync_phase);
+
+enum ds_return dal_display_service_target_power_control(
+ struct display_service *ds,
+ uint32_t display_index,
+ bool power_on);
+
+enum ds_return dal_display_service_power_down_active_hw(
+ struct display_service *ds,
+ enum dal_video_power_state state);
+
+enum ds_return dal_display_service_mem_request_control(
+ struct display_service *ds,
+ uint32_t display_index,
+ bool enable);
+
+enum ds_return dal_display_service_set_multimedia_pass_through_mode(
+ struct display_service *ds,
+ uint32_t display_index,
+ bool passThrough);
+
+enum ds_return dal_display_service_set_palette(
+ struct display_service *ds,
+ uint32_t display_index,
+ const struct ds_devclut *palette,
+ const uint32_t start,
+ const uint32_t length);
+
+enum ds_return dal_display_service_apply_pix_clk_range(
+ struct display_service *ds,
+ uint32_t display_index,
+ struct pixel_clock_safe_range *range);
+
+enum ds_return dal_display_service_get_safe_pix_clk(
+ struct display_service *ds,
+ uint32_t display_index,
+ uint32_t *pix_clk_khz);
+
+enum ds_return dal_display_service_apply_refreshrate_adjustment(
+ struct display_service *ds,
+ uint32_t display_index,
+ enum ds_refreshrate_adjust_action action,
+ struct ds_refreshrate *refreshrate);
+
+enum ds_return dal_display_service_pre_ddc(
+ struct display_service *ds,
+ uint32_t display_index);
+
+enum ds_return dal_display_service_post_ddc(
+ struct display_service *ds,
+ uint32_t display_index);
+
+enum ds_return dal_display_service_backlight_control(
+ struct display_service *ds,
+ uint32_t display_index,
+ bool enable);
+
+enum ds_return dal_display_service_get_backlight_user_level(
+ struct display_service *ds,
+ uint32_t display_index,
+ uint32_t *level);
+
+enum ds_return dal_display_service_get_backlight_effective_level(
+ struct display_service *ds,
+ uint32_t display_index,
+ uint32_t *level);
+
+enum ds_return dal_display_service_enable_hpd(
+ struct display_service *ds,
+ uint32_t display_index);
+
+enum ds_return dal_display_service_disable_hpd(
+ struct display_service *ds,
+ uint32_t display_index);
+
+enum ds_return dal_display_service_get_min_mem_channels(
+ struct display_service *ds,
+ const struct path_mode_set *path_mode_set,
+ uint32_t mem_channels_num,
+ uint32_t *min_mem_channels_num);
+
+enum ds_return dal_display_service_enable_advanced_request(
+ struct display_service *ds,
+ bool enable);
+
+/*Audio related*/
+enum ds_return dal_display_service_enable_audio_endpoint(
+ struct display_service *ds,
+ uint32_t display_index,
+ bool enable);
+
+enum ds_return dal_display_service_mute_audio_endpoint(
+ struct display_service *ds,
+ uint32_t display_index,
+ bool mute);
+
+bool dal_display_service_calc_view_port_for_wide_display(
+ struct display_service *ds,
+ uint32_t display_index,
+ const struct ds_view_port *set_view_port,
+ struct ds_get_view_port *get_view_port);
+
+#endif /* __DISPLAY_SERVICE_INTERFACE_H__ */
diff --git a/drivers/gpu/drm/amd/dal/include/overlay_interface.h b/drivers/gpu/drm/amd/dal/include/overlay_interface.h
new file mode 100644
index 000000000000..c33bd73610e7
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/include/overlay_interface.h
@@ -0,0 +1,137 @@
+/*
+ * 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_OVERLAY_INTERFACE_H__
+#define __DAL_OVERLAY_INTERFACE_H__
+
+#include "include/overlay_types.h"
+#include "include/display_service_types.h"
+
+struct ds_overlay;
+struct path_mode_set;
+struct path_mode;
+struct view;
+
+bool dal_ds_overlay_is_active(
+ struct ds_overlay *ovl,
+ uint32_t display_index);
+
+uint32_t dal_ds_overlay_get_controller_handle(
+ struct ds_overlay *ovl,
+ uint32_t display_index);
+
+enum ds_return dal_ds_overlay_alloc(
+ struct ds_overlay *ovl,
+ struct path_mode_set *path_mode_set,
+ uint32_t display_index,
+ struct view *view,
+ struct overlay_data *data);
+
+enum ds_return dal_ds_overlay_validate(
+ struct ds_overlay *ovl,
+ struct path_mode_set *path_mode_set,
+ uint32_t display_index,
+ struct view *view,
+ struct overlay_data *data);
+
+enum ds_return dal_ds_overlay_free(
+ struct ds_overlay *ovl,
+ struct path_mode_set *path_mode_set,
+ uint32_t display_index);
+
+enum ds_return dal_ds_overlay_get_info(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ enum overlay_color_space *color_space,
+ enum overlay_backend_bpp *backend_bpp,
+ enum overlay_alloc_option *alloc_option,
+ enum overlay_format *surface_format);
+
+enum ds_return dal_ds_overlay_set_otm(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ const struct path_mode *current_path_mode);
+
+enum ds_return dal_ds_overlay_reset_otm(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ struct path_mode **saved_path_mode);
+
+/**is in overlay theater mode*/
+bool dal_ds_overlay_is_in_otm(
+ struct ds_overlay *ovl,
+ uint32_t display_index);
+
+void dal_ds_overlay_set_matrix(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ const struct overlay_color_matrix *matrix);
+
+void dal_ds_overlay_reset_matrix(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ enum overlay_csc_matrix_type type);
+
+const struct overlay_color_matrix *dal_ds_overlay_get_matrix(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ enum overlay_csc_matrix_type type);
+
+bool dal_ds_overlay_set_color_space(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ enum overlay_color_space space);
+
+bool dal_ds_overlay_get_display_pixel_encoding(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ enum display_pixel_encoding *pixel_encoding);
+
+bool dal_ds_overlay_set_display_pixel_encoding(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ enum display_pixel_encoding pixel_encoding);
+
+bool dal_ds_overlay_reset_display_pixel_encoding(
+ struct ds_overlay *ovl,
+ uint32_t display_index);
+
+/*After Set Overlay Theatre Mode (OTM) on a display path,
+ * saving the passed setting of Gpu scaling option for later restore*/
+enum ds_return dal_ds_overlay_save_gpu_scaling_before_otm(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ int32_t timing_sel_before_otm);
+
+/* After reset Overlay Theatre Mode (OTM) on a display path,
+ * returning the previous Gpu scaling option by SetOverlayTheatreMode*/
+enum ds_return dal_ds_overlay_get_gpu_scaling_before_otm(
+ struct ds_overlay *ovl,
+ uint32_t display_index,
+ int32_t *timing_sel_before_otm);
+
+uint32_t dal_ds_overlay_get_num_of_allowed(struct ds_overlay *ovl);
+
+#endif /* __DAL_OVERLAY_INTERFACE_H__ */
diff --git a/drivers/gpu/drm/amd/dal/include/overlay_types.h b/drivers/gpu/drm/amd/dal/include/overlay_types.h
new file mode 100644
index 000000000000..c001edf69f25
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/include/overlay_types.h
@@ -0,0 +1,164 @@
+/*
+ * 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_OVERLAY_TYPES_H__
+#define __DAL_OVERLAY_TYPES_H__
+
+enum overlay_color_space {
+ OVERLAY_COLOR_SPACE_UNINITIALIZED,
+ OVERLAY_COLOR_SPACE_RGB, /* the first*/
+ OVERLAY_COLOR_SPACE_BT601,
+ OVERLAY_COLOR_SPACE_BT709, /* the last*/
+ OVERLAY_COLOR_SPACE_INVALID,
+
+ /* flag the first and last*/
+ OVERLAY_COLOR_SPACE_BEGIN = OVERLAY_COLOR_SPACE_RGB,
+ OVERLAY_COLOR_SPACE_END = OVERLAY_COLOR_SPACE_BT709,
+};
+
+enum overlay_backend_bpp {
+ OVERLAY_BACKENDBPP_UNINITIALIZED,
+
+ OVERLAY_BACKEND_BPP_32_FULL_BANDWIDTH,/* the first*/
+ OVERLAY_BACKEND_BPP_16_FULL_BANDWIDTH,
+ OVERLAY_BACKEND_BPP_32_HALF_BANDWIDTH,/* the last*/
+
+ OVERLAY_BACKEND_BPP_INVALID,
+
+ /* flag the first and last*/
+ OVERLAY_BACKEND_BPP_BEGIN = OVERLAY_BACKEND_BPP_32_FULL_BANDWIDTH,
+ OVERLAY_BACKEND_BPP_END = OVERLAY_BACKEND_BPP_32_HALF_BANDWIDTH,
+};
+
+enum overlay_alloc_option {
+ OVERLAY_ALLOC_OPTION_UNINITIALIZED,
+
+ OVERLAY_ALLOC_OPTION_APPLY_OVERLAY_CSC, /* the first*/
+ OVERLAY_ALLOC_OPTION_APPLY_DESKTOP_CSC, /* the last*/
+
+ OVERLAY_ALLOC_OPTION_INVALID,
+
+ /* flag the first and last*/
+ OVERLAY_ALLOC_OPTION_BEGIN = OVERLAY_ALLOC_OPTION_APPLY_OVERLAY_CSC,
+ OVERLAY_ALLOC_OPTION_END = OVERLAY_ALLOC_OPTION_APPLY_DESKTOP_CSC,
+};
+
+enum overlay_format {
+ OVERLAY_FORMAT_UNINITIALIZED,
+ OVERLAY_FORMAT_YUY2,
+ OVERLAY_FORMAT_UYVY,
+ OVERLAY_FORMAT_RGB565,
+ OVERLAY_FORMAT_RGB555,
+ OVERLAY_FORMAT_RGB32,
+ OVERLAY_FORMAT_YUV444,
+ OVERLAY_FORMAT_RGB32_2101010,
+
+ OVERLAY_FORMAT_INVALID,
+
+ /* flag the first and last*/
+ OVERLAY_FORMAT_BEGIN = OVERLAY_FORMAT_YUY2,
+ OVERLAY_FORMAT_END = OVERLAY_FORMAT_RGB32_2101010,
+};
+
+enum display_pixel_encoding {
+ DISPLAY_PIXEL_ENCODING_UNDEFINED = 0,
+ DISPLAY_PIXEL_ENCODING_RGB,
+ DISPLAY_PIXEL_ENCODING_YCBCR422,
+ DISPLAY_PIXEL_ENCODING_YCBCR444
+};
+
+union overlay_data_status {
+ uint32_t u32all;
+ struct {
+ uint32_t COLOR_SPACE_SET:1;
+ uint32_t BACKEND_BPP:1;
+ uint32_t ALLOC_OPTION:1;
+ uint32_t SURFACE_FORMAT:1;
+ uint32_t PIXEL_ENCODING:1;
+ uint32_t reserved:27;
+
+ } bits;
+};
+
+struct overlay_data {
+ enum overlay_color_space color_space;
+ enum overlay_backend_bpp backend_bpp;
+ enum overlay_alloc_option alloc_option;
+ enum overlay_format surface_format;
+};
+
+enum overlay_csc_matrix_type {
+ OVERLAY_CSC_MATRIX_NOTDEFINED = 0,
+ OVERLAY_CSC_MATRIX_BT709,
+ OVERLAY_CSC_MATRIX_BT601,
+ OVERLAY_CSC_MATRIX_SMPTE240,
+ OVERLAY_CSC_MATRIX_SRGB,
+};
+
+#define DEFAULT_APP_MATRIX_DIVIDER 10000
+#define MAX_OVL_MATRIX_COUNTS 2
+#define OVL_BT709 0
+#define OVL_BT601 1
+
+#define OVL_MATRIX_ITEM 9
+#define OVL_MATRIX_OFFSET_ITEM 3
+
+struct overlay_color_matrix {
+ enum overlay_csc_matrix_type csc_matrix;
+/*3*3 Gamut Matrix (value is the real value * M_GAMUT_PRECISION_MULTIPLIER)*/
+ int32_t matrix_settings[OVL_MATRIX_ITEM];
+ int32_t offsets[OVL_MATRIX_OFFSET_ITEM];
+};
+
+enum setup_adjustment_ovl_value_type {
+ SETUP_ADJUSTMENT_MIN,
+ SETUP_ADJUSTMENT_MAX,
+ SETUP_ADJUSTMENT_DEF,
+ SETUP_ADJUSTMENT_CURRENT,
+ SETUP_ADJUSTMENT_BUNDLE_MIN,
+ SETUP_ADJUSTMENT_BUNDLE_MAX,
+ SETUP_ADJUSTMENT_BUNDLE_DEF,
+ SETUP_ADJUSTMENT_BUNDLE_CURRENT
+};
+
+struct overlay_parameter {
+ union {
+ uint32_t u32all;
+ struct {
+ uint32_t VALID_OVL_COLOR_SPACE:1;
+ uint32_t VALID_VALUE_TYPE:1;
+ uint32_t VALID_OVL_SURFACE_FORMAT:1;
+ uint32_t CONFIG_IS_CHANGED:1;
+ uint32_t reserved:28;
+
+ } bits;
+ };
+ /*currently colorSpace here packed, continue this list*/
+ enum overlay_color_space color_space;
+ enum setup_adjustment_ovl_value_type value_type;
+ enum overlay_format surface_format;
+};
+
+#endif /* OVERLAY_TYPES_H_ */