summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarry Wentland <harry.wentland@amd.com>2015-07-31 22:12:11 -0400
committerAlex Deucher <alexander.deucher@amd.com>2015-09-21 17:45:16 -0400
commitb4f181b117dbc578a37500e18a4533335559e9d5 (patch)
tree603fc41a885c1c96a2e9fe72a5e2888b0f6ad1c0
parent7a366fa8360a48b1d22e40bf170c21e9fb1be2ee (diff)
amd/dal: DAL Interface
This abstracts our internal hw programming sequences so we can (a) test it in user space and (b) use it more easily with current and future kernel modesetting APIs such as atomic. SW Layer /===============================================================\ | DAL Display Timing Mode Asic | | Interface 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/Makefile6
-rw-r--r--drivers/gpu/drm/amd/dal/include/bm_calcs.h31
-rw-r--r--drivers/gpu/drm/amd/dal/include/dal_interface.h261
-rw-r--r--drivers/gpu/drm/amd/dal/include/timing_list_query_interface.h83
-rw-r--r--drivers/gpu/drm/amd/dal/interface/Makefile10
-rw-r--r--drivers/gpu/drm/amd/dal/interface/dal.c1665
-rw-r--r--drivers/gpu/drm/amd/dal/interface/timing_list_query.c371
7 files changed, 2424 insertions, 3 deletions
diff --git a/drivers/gpu/drm/amd/dal/Makefile b/drivers/gpu/drm/amd/dal/Makefile
index b95ba1e51f55..d99e75f9b9ca 100644
--- a/drivers/gpu/drm/amd/dal/Makefile
+++ b/drivers/gpu/drm/amd/dal/Makefile
@@ -8,9 +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_service display_path encoder gpio gpu \
- hw_sequencer i2caux irq link_service mode_manager timing_service \
- topology
+ controller dcs display_path display_service encoder gpio gpu \
+ hw_sequencer i2caux interface link_service mode_manager timing_service \
+ topology irq
AMD_DAL = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DAL_PATH)/,$(DAL_LIBS)))
diff --git a/drivers/gpu/drm/amd/dal/include/bm_calcs.h b/drivers/gpu/drm/amd/dal/include/bm_calcs.h
new file mode 100644
index 000000000000..4a5e2507da91
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/include/bm_calcs.h
@@ -0,0 +1,31 @@
+/*
+ * 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_BM_CALCS_H__
+#define __DAL_BM_CALCS_H__
+
+#include "bandwidth_manager_types.h"
+
+#endif /* __DAL_BM_CALCS_H__ */
diff --git a/drivers/gpu/drm/amd/dal/include/dal_interface.h b/drivers/gpu/drm/amd/dal/include/dal_interface.h
new file mode 100644
index 000000000000..4b7dca42e657
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/include/dal_interface.h
@@ -0,0 +1,261 @@
+/*
+ * 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_INTERFACE_H__
+#define __DAL_INTERFACE_H__
+
+#include "dal_types.h"
+#include "dal_asic_id.h"
+#include "set_mode_types.h"
+#include "plane_types.h"
+#include "dcs_types.h"
+#include "timing_list_query_interface.h"
+
+struct dal;
+struct dal_to_path_mode_set;
+struct surface_attributes;
+struct surface_address;
+struct view_port_area;
+struct dal_timing_list_query;
+struct topology_mgr;
+struct power_to_dal_info;
+struct address_info;
+struct wifi_display_caps;
+struct path_mode;
+struct path_mode_set;
+
+struct dal *dal_create(struct dal_init_data *init);
+void dal_destroy(struct dal **dal);
+
+/**
+ * Enable the DAL instance after resume from (S3/S4)
+ *
+ * Enables instance of the DAL specific to an adapter after resume.
+ * The function sets up the display mapping based on appropriate boot-up
+ * behaviour.
+ */
+void dal_resume(struct dal *dal);
+
+/* HW Capability queries */
+uint32_t dal_get_controllers_number(struct dal *dal);
+uint32_t dal_get_connected_targets_vector(struct dal *dal);
+uint32_t dal_get_cofunctional_targets_number(struct dal *dal);
+
+/* Return a bitvector of *all* Display Paths. */
+uint32_t dal_get_supported_displays_vector(struct dal *dal);
+/* Return a bitvector of a *single* Display Path. */
+uint32_t dal_get_display_vector_by_index(struct dal *dal,
+ uint32_t display_index);
+
+uint32_t dal_get_a_display_index_by_type(
+ struct dal *dal,
+ uint32_t display_type);
+
+enum signal_type dal_get_display_signal(
+ struct dal *dal,
+ uint32_t display_index);
+
+const uint8_t *dal_get_display_edid(
+ struct dal *dal,
+ uint32_t display_index,
+ uint32_t *buff_size);
+
+void dal_get_screen_info(
+ struct dal *dal,
+ uint32_t display_index,
+ struct edid_screen_info *screen_info);
+
+/* TODO: implement later
+bool dal_get_display_output_descriptor (struct dal *dal,
+ uint32_t display_index,
+ struct dal_display_output_descriptor *display_descriptor);
+*/
+
+/**************** Mode Validate / Set ****************/
+bool dal_set_path_mode(struct dal *dal,
+ const struct path_mode_set *pms);
+
+bool dal_reset_path_mode(struct dal *dal,
+ const uint32_t displays_num,
+ const uint32_t *display_indexes);
+
+struct mode_query;
+void dal_pin_active_path_modes(
+ struct dal *dal,
+ void *param,
+ uint32_t display_index,
+ void (*func)(void *, const struct path_mode *));
+
+/******************** PowerPlay ********************/
+
+bool dal_pre_adapter_clock_change(struct dal *dal,
+ struct power_to_dal_info *clks_info);
+
+bool dal_post_adapter_clock_change(struct dal *dal);
+
+/***************** Power Control *****************/
+void dal_set_display_dpms(
+ struct dal *dal,
+ uint32_t display_index,
+ uint32_t state);
+
+void dal_set_power_state(
+ struct dal *dal,
+ uint32_t power_state,
+ uint32_t video_power_state);
+
+void dal_set_blanking(struct dal *dal, uint32_t display_index, bool blank);
+void dal_shut_down_display_block(struct dal *dal);
+
+/***************** Brightness Interface *****************/
+bool dal_set_backlight_level(
+ struct dal *dal,
+ uint32_t display_index,
+ uint32_t brightness);
+bool dal_get_backlight_level_old(
+ struct dal *dal,
+ uint32_t display_index,
+ void *adjustment);
+bool dal_backlight_control_on(struct dal *dal);
+bool dal_backlight_control_off(struct dal *dal);
+
+/***************** Brightness and color Control *****************/
+void dal_set_palette(
+ struct dal *dal,
+ uint32_t display_index,
+ struct dal_dev_c_lut palette,
+ uint32_t start,
+ uint32_t length);
+
+bool dal_set_gamma(
+ struct dal *dal,
+ uint32_t display_index,
+ struct raw_gamma_ramp *gamma);
+
+/* Active Stereo Interface */
+bool dal_control_stereo(struct dal *dal, uint32_t display_index, bool enable);
+
+/* Disable All DC Pipes - blank CRTC and disable memory requests */
+void dal_disable_all_dc_pipes(struct dal *dal);
+
+/*
+uint32_t dal_get_interrupt_source(const struct dal_display_index_set *set,
+ uint64_t *irq_source);
+*/
+
+/* Timing List Query */
+struct dal_timing_list_query *dal_create_timing_list_query(struct dal *dal,
+ uint32_t display_index);
+
+/*hard code color square at CRTC0 for HDMI light up*/
+void dal_set_crtc_test_pattern(struct dal *dal);
+
+/* returns the display_index associated (that generated) to irq source */
+enum dal_irq_source;
+uint32_t dal_get_display_index_from_int_src(
+ struct dal *dal,
+ enum dal_irq_source src);
+
+/* return crtc scanout v/h counter, return if inside v_blank*/
+uint32_t dal_get_crtc_scanoutpos(
+ struct dal *dal,
+ uint32_t display_index,
+ int32_t *vpos,
+ int32_t *hpos);
+
+/* Return IRQ Source for Controller currently assigned to the Path. */
+enum dal_irq_source dal_get_vblank_irq_src_from_display_index(struct dal *dal,
+ uint32_t display_index);
+enum dal_irq_source dal_get_pflip_irq_src_from_display_index(struct dal *dal,
+ uint32_t display_index,
+ uint32_t plane_no);
+
+void dal_set_vblank_irq(struct dal *dal, uint32_t display_index, bool enable);
+
+
+struct topology;
+enum query_option;
+
+struct mode_query *dal_get_mode_query(
+ struct dal *dal,
+ struct topology *tp,
+ enum query_option query_option);
+
+struct mode_manager *dal_get_mode_manager(struct dal *dal);
+
+uint32_t dal_wifi_display_acquire(
+ struct dal *dal,
+ uint8_t *edid_data,
+ uint32_t edid_size,
+ struct dal_remote_display_receiver_capability *caps,
+ uint32_t *display_index);
+
+uint32_t dal_wifi_display_release(
+ struct dal *dal,
+ uint32_t *display_index);
+
+/* Get the current vertical blank counts for given CRTC. */
+uint32_t dal_get_vblank_counter(struct dal *dal, int disp_idx);
+
+/* Surface programming interface */
+
+/* TODO: move these below to separate header */
+bool dal_set_cursor_position(
+ struct dal *dal,
+ const uint32_t display_index,
+ const struct cursor_position *position
+ );
+
+bool dal_set_cursor_attributes(
+ struct dal *dal,
+ const uint32_t display_index,
+ const struct cursor_attributes *attributes
+ );
+
+bool dal_setup_plane_configurations(
+ struct dal *dal,
+ uint32_t num_planes,
+ struct plane_config *configs);
+
+bool dal_update_plane_addresses(
+ struct dal *dal,
+ uint32_t num_planes,
+ struct plane_addr_flip_info *info);
+
+bool dal_validate_plane_configurations(struct dal *dal,
+ int num_planes,
+ const struct plane_config *pl_config,
+ bool *supported);
+
+void dal_interrupt_set(struct dal *dal, enum dal_irq_source src, bool enable);
+
+void dal_interrupt_ack(struct dal *dal, enum dal_irq_source src);
+
+enum dal_irq_source dal_interrupt_to_irq_source(
+ struct dal *dal,
+ uint32_t src_id,
+ uint32_t ext_id);
+
+#endif
diff --git a/drivers/gpu/drm/amd/dal/include/timing_list_query_interface.h b/drivers/gpu/drm/amd/dal/include/timing_list_query_interface.h
new file mode 100644
index 000000000000..6f3564c58c24
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/include/timing_list_query_interface.h
@@ -0,0 +1,83 @@
+/*
+ * 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_TIMING_LIST_QUERY_INTERFACE_H__
+#define __DAL_TIMING_LIST_QUERY_INTERFACE_H__
+
+/* External dependencies */
+#include "include/timing_service_types.h"
+#include "include/dcs_interface.h"
+
+/* Forward declarations */
+struct dal;
+struct dal_timing_list_query;
+
+enum timing_support_level {
+ TIMING_SUPPORT_LEVEL_UNDEFINED,
+ /* assumed to be guaranteed supported by display,
+ * usually one timing is marked as native */
+ TIMING_SUPPORT_LEVEL_NATIVE,
+ /* user wants DAL to drive this timing as if Display supports it */
+ TIMING_SUPPORT_LEVEL_GUARANTEED,
+ /* user wants DAL to drive this timing even if display
+ * may not support it */
+ TIMING_SUPPORT_LEVEL_NOT_GUARANTEED
+};
+
+struct timing_list_query_init_data {
+ struct dal *dal; /* an instance of DAL */
+ struct timing_service *timing_srv;
+ struct dcs *dcs;
+ uint32_t display_index;
+};
+
+struct dal_timing_list_query *dal_timing_list_query_create(
+ struct timing_list_query_init_data *init_data);
+
+void dal_timing_list_query_destroy(struct dal_timing_list_query **tlsq);
+
+/* Get count of mode timings in the list. */
+uint32_t dal_timing_list_query_get_mode_timing_count(
+ const struct dal_timing_list_query *tlsq);
+
+const struct mode_timing *dal_timing_list_query_get_mode_timing_at_index(
+ const struct dal_timing_list_query *tlsq,
+ uint32_t index);
+
+/**
+ *****************************************************************************
+ * timing_list_query_add_timing() is used to add timing to a target timing
+ * mode list.
+ * In case device disconnected, the previously added modes will be stay with
+ * the target mode list until a newly connected device arrival and added
+ * timing will be removed automatically by DAL.
+ *****************************************************************************
+ */
+bool dal_timing_list_query_add_timing(struct dal_timing_list_query *tlsq,
+ const struct crtc_timing *crtc_timing,
+ enum timing_support_level support_level);
+
+
+#endif /* __DAL_TIMING_LIST_QUERY_INTERFACE_H__ */
diff --git a/drivers/gpu/drm/amd/dal/interface/Makefile b/drivers/gpu/drm/amd/dal/interface/Makefile
new file mode 100644
index 000000000000..cde4ab301efe
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/interface/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the 'dal_services' sub-component of DAL.
+# It provides the entry point for all DAL services to the driver.
+
+
+INTERFACE = dal.o timing_list_query.o
+
+AMD_DAL_INTERFACE = $(addprefix $(AMDDALPATH)/interface/,$(INTERFACE))
+
+AMD_DAL_FILES += $(AMD_DAL_INTERFACE)
diff --git a/drivers/gpu/drm/amd/dal/interface/dal.c b/drivers/gpu/drm/amd/dal/interface/dal.c
new file mode 100644
index 000000000000..115ab3c00dd2
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/interface/dal.c
@@ -0,0 +1,1665 @@
+/*
+ * 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/dal_interface.h"
+#include "include/adapter_service_interface.h"
+#include "include/timing_service_interface.h"
+#include "include/topology_mgr_interface.h"
+#include "include/gpu_interface.h"
+#include "include/timing_list_query_interface.h"
+#include "include/display_service_interface.h"
+#include "include/set_mode_interface.h"
+#include "include/adjustment_interface.h"
+#include "include/display_path_interface.h"
+#include "include/controller_interface.h"
+#include "include/hw_sequencer_interface.h"
+#include "include/logger_interface.h"
+#include "include/mode_manager_interface.h"
+#include "include/dcs_interface.h"
+#include "include/irq_service_interface.h"
+
+/*
+* DAL - Display Abstraction Layer
+* represents the main high level object that provides
+* abstracted display services. One such object needs to
+* be created per GPU ASIC.
+*/
+
+struct dal {
+ struct dal_init_data init_data;
+ struct dal_context dal_context;
+ struct adapter_service *adapter_srv;
+ struct timing_service *timing_srv;
+ struct topology_mgr *topology_mgr;
+ struct display_service *display_service;
+ struct hw_sequencer *hws;
+ struct mode_manager *mm;
+ struct irq_service *irqs;
+};
+
+/* debugging macro definitions */
+#define DAL_IF_TRACE() \
+ dal_logger_write(dal_context->logger, \
+ LOG_MAJOR_INTERFACE_TRACE, \
+ LOG_MINOR_COMPONENT_DAL_INTERFACE, \
+ "DAL_IF_TRACE: %s()\n", __func__)
+
+#define DAL_IF_NOT_IMPLEMENTED() \
+ DAL_LOGGER_NOT_IMPL(LOG_MINOR_COMPONENT_DAL_INTERFACE, \
+ "DAL_IF:%s()\n", __func__)
+
+#define DAL_IF_ERROR(...) \
+ dal_logger_write(dal_context->logger, \
+ LOG_MAJOR_ERROR, \
+ LOG_MINOR_COMPONENT_DAL_INTERFACE, \
+ __VA_ARGS__)
+
+enum {
+ MAX_PLANE_NUM = 4
+};
+/******************************************************************************
+ Declarations for Timing List Query.
+******************************************************************************/
+
+/******************************************************************************
+ Prototypes of private functions.
+******************************************************************************/
+static bool dal_construct(struct dal_init_data *init,
+ struct dal *dal);
+static void dal_destruct(struct dal *dal);
+static struct adapter_service *create_as(
+ struct dal *dal);
+static bool dal_enable(struct dal *dal);
+
+/******************************************************************************
+ Implementation of the API provided by DAL.
+******************************************************************************/
+struct dal *dal_create(struct dal_init_data *init)
+{
+ struct dal *dal_instance = NULL;
+
+ /* DAL_IF_TRACE();*/
+
+ dal_instance = dal_alloc(sizeof(*dal_instance));
+
+ if (NULL == dal_instance) {
+ /*DAL_IF_ERROR("%s: failed to allocate %ld bytes!\n",
+ __func__, sizeof(*dal_instance)); */
+ return NULL;
+ }
+
+ if (!dal_construct(init, dal_instance)) {
+ dal_free(dal_instance);
+ return NULL;
+ }
+
+ return dal_instance;
+}
+
+void dal_destroy(struct dal **dal)
+{
+ struct dal_context *dal_context = NULL;
+
+ if (dal == NULL || *dal == NULL)
+ return;
+ dal_context = &((*dal)->dal_context);
+
+ DAL_IF_TRACE();
+
+ /***************************************
+ * deallocate all subcomponents of DAL
+ ***************************************/
+ dal_destruct(*dal);
+
+ /*************************
+ * deallocate DAL itself
+ *************************/
+ dal_free(*dal);
+ *dal = NULL;
+}
+
+static bool dal_construct(struct dal_init_data *init,
+ struct dal *dal_instance)
+{
+ struct dal_context *dal_context = &dal_instance->dal_context;
+
+ dal_instance->init_data = *init;
+ dal_instance->dal_context.driver_context = init->driver;
+ dal_instance->dal_context.cgs_device = init->cgs_device;
+
+ /* Logger */
+
+ dal_instance->dal_context.logger = dal_logger_create();
+
+ if (!dal_instance->dal_context.logger) {
+ /* can *not* call logger. call base driver 'print error' */
+ dal_error("%s: failed to create Logger!\n", __func__);
+ goto logger_fail;
+ }
+
+ /* Adapter Service */
+
+ dal_instance->adapter_srv = create_as(dal_instance);
+
+ if (!dal_instance->adapter_srv) {
+ DAL_IF_ERROR("%s: create_as() failed!\n", __func__);
+ goto as_fail;
+ }
+
+ /* Initialise HW controlled by Adapter Service */
+ if (false == dal_adapter_service_initialize_hw_data(
+ dal_instance->adapter_srv)) {
+ DAL_IF_ERROR("%s: dal_adapter_service_initialize_hw_data() failed!\n",
+ __func__);
+ /* Note that AS exist, so have to destroy it.*/
+ goto ts_fail;
+ }
+
+ /* Timing Service */
+ dal_instance->timing_srv =
+ dal_timing_service_create(
+ &dal_instance->dal_context,
+ true);
+
+ if (!dal_instance->timing_srv) {
+ DAL_IF_ERROR(
+ "%s: dal_timing_service_create() failed!\n",
+ __func__);
+ goto ts_fail;
+ }
+
+ {
+ struct hws_init_data hws_init_data;
+
+ hws_init_data.as = dal_instance->adapter_srv;
+ hws_init_data.dal_context = &dal_instance->dal_context;
+
+ dal_instance->hws = dal_hw_sequencer_create(&hws_init_data);
+
+ if (!dal_instance->hws) {
+ DAL_IF_ERROR("%s: dal_hw_sequencer_create() failed!\n",
+ __func__);
+ goto hws_fail;
+ }
+ }
+
+ {
+ struct mode_manager_init_data init_data;
+
+ init_data.as = dal_instance->adapter_srv;
+ init_data.default_modes =
+ dal_timing_service_get_default_mode_list(
+ dal_instance->timing_srv);
+ init_data.dal_context = &dal_instance->dal_context;
+ dal_instance->mm = dal_mode_manager_create(&init_data);
+
+ if (!dal_instance->mm)
+ goto mm_fail;
+ }
+
+ {
+ struct topology_mgr_init_data tm_init_data;
+
+ dal_memset(&tm_init_data, 0, sizeof(tm_init_data));
+
+ /* Topology Manager */
+ tm_init_data.dal_context = &dal_instance->dal_context;
+ tm_init_data.adapter_srv = dal_instance->adapter_srv;
+ tm_init_data.timing_srv = dal_instance->timing_srv;
+ tm_init_data.hwss_srvr = dal_instance->hws;
+ tm_init_data.mm = dal_instance->mm;
+
+ dal_instance->topology_mgr = dal_tm_create(&tm_init_data);
+
+ if (!dal_instance->topology_mgr) {
+ DAL_IF_ERROR("%s: dal_tm_create() failed!\n", __func__);
+ goto tm_fail;
+ }
+
+ /* TODO: Set embedded display index in AS for backlight ctrl?*/
+ }
+
+ {
+ struct ds_init_data ds_init_data = { 0 };
+
+ ds_init_data.dal_context = &dal_instance->dal_context;
+ ds_init_data.as = dal_instance->adapter_srv;
+ ds_init_data.ts = dal_instance->timing_srv;
+ ds_init_data.tm = dal_instance->topology_mgr;
+ ds_init_data.hwss = dal_instance->hws;
+
+ ds_init_data.view_port_alignment.x_start_alignment =
+ init->vp_alignment.x_start_alignment;
+ ds_init_data.view_port_alignment.x_width_size_alignment =
+ init->vp_alignment.x_width_size_alignment;
+ ds_init_data.view_port_alignment.y_height_size_alignment =
+ init->vp_alignment.y_height_size_alignment;
+ ds_init_data.view_port_alignment.y_start_alignment =
+ init->vp_alignment.y_start_alignment;
+
+ dal_instance->display_service =
+ dal_display_service_create(&ds_init_data);
+
+ if (!dal_instance->display_service) {
+ DAL_IF_ERROR(
+ "%s: dal_display_service_create() failed!\n",
+ __func__);
+ goto ds_fail;
+ }
+ }
+
+ {
+ struct irq_service_init_data init_data;
+
+ init_data.ctx = dal_context;
+ dal_instance->irqs =
+ dal_irq_service_create(
+ dal_adapter_service_get_dce_version(
+ dal_instance->adapter_srv),
+ &init_data);
+
+ if (!dal_instance->irqs)
+ goto irqs_fail;
+ }
+
+ dal_mode_manager_set_ds_dispatch(
+ dal_instance->mm,
+ dal_display_service_get_set_mode_interface(
+ dal_instance->display_service));
+
+ if (!dal_timing_service_initialize_filters(
+ dal_instance->timing_srv,
+ dal_display_service_get_set_mode_interface(
+ dal_instance->display_service)))
+ goto fail;
+
+ /* try to "enable" DAL */
+ if (dal_enable(dal_instance))
+ return true;
+
+fail:
+ dal_irq_service_destroy(&dal_instance->irqs);
+irqs_fail:
+ dal_display_service_destroy(&dal_instance->display_service);
+ds_fail:
+ dal_tm_destroy(&dal_instance->topology_mgr);
+tm_fail:
+ dal_mode_manager_destroy(&dal_instance->mm);
+mm_fail:
+ dal_hw_sequencer_destroy(&dal_instance->hws);
+hws_fail:
+ dal_timing_service_destroy(&dal_instance->timing_srv);
+ts_fail:
+ dal_adapter_service_destroy(&dal_instance->adapter_srv);
+as_fail:
+ dal_logger_destroy(&dal_instance->dal_context.logger);
+logger_fail:
+
+ return false;
+}
+
+static void release_hw(struct dal *dal)
+{
+ dal_tm_release_hw(dal->topology_mgr);
+}
+
+static void dal_destruct(struct dal *dal)
+{
+ release_hw(dal);
+
+ dal_irq_service_destroy(&dal->irqs);
+
+ dal_adapter_service_destroy(&dal->adapter_srv);
+
+ dal_timing_service_destroy(&dal->timing_srv);
+
+ dal_hw_sequencer_destroy(&dal->hws);
+
+ dal_display_service_destroy(&dal->display_service);
+
+ dal_tm_destroy(&dal->topology_mgr);
+
+ dal_logger_destroy(&dal->dal_context.logger);
+
+ dal_mode_manager_destroy(&dal->mm);
+}
+
+/**
+ *****************************************************************************
+ * Function: dal_enable
+ *
+ * @brief
+ * 1. Enable DAL instance and initialise the display HW.
+ * 2. Do initial detection.
+ *
+ * @return
+ * If DAL instance is enabled successfully, return true,
+ * otherwise, return false.
+ *
+ *****************************************************************************
+ */
+static bool dal_enable(struct dal *dal)
+{
+ enum tm_result tm_rc;
+ struct topology_mgr *tm_mgr = dal->topology_mgr;
+ struct dal_context *dal_context = &dal->dal_context;
+
+ DAL_IF_TRACE();
+
+ /* TODO: call Display Service to notify all subcomponents
+ * about initial display configuration. */
+
+ /* call TM to initialise HW */
+ dal_tm_set_current_power_state(tm_mgr, DAL_VIDEO_POWER_UNSPECIFIED);
+
+ tm_rc = dal_tm_init_hw(tm_mgr);
+
+ if (TM_RESULT_SUCCESS == tm_rc) {
+ /*blank all pipe.--> stop memory request to frame buffer*/
+ dal_tm_disable_all_dcp_pipes(tm_mgr);
+
+ /* no error */
+ /* call TM to detect connected displays */
+ dal_tm_do_initial_detection(tm_mgr);
+
+ /* Only if *everything* is initialised successfully, register
+ * to receive HPD interrupts. */
+ tm_rc = dal_tm_register_for_display_detection_interrupt(tm_mgr);
+ }
+
+ if (TM_RESULT_SUCCESS != tm_rc)
+ /* error occurred */
+ return false;
+
+ return true;
+}
+
+/*
+ * Enable the DAL instance after resume
+ *
+ * Enables instance of the DAL specific to an adapter after resume.
+ * The function sets up the display mapping based on appropriate boot-up
+ * behavior.
+ */
+void dal_resume(struct dal *dal)
+{
+ struct dal_context *dal_context = &dal->dal_context;
+
+ DAL_IF_TRACE();
+
+ dal_tm_do_complete_detection(dal->topology_mgr,
+ DETECTION_METHOD_DESTRUCTIVE,
+ false);
+}
+
+/* HW Capability queries */
+uint32_t dal_get_controllers_number(struct dal *dal)
+{
+ struct dal_context *dal_context = &dal->dal_context;
+
+ DAL_IF_TRACE();
+
+ return dal_tm_get_num_functional_controllers(dal->topology_mgr);
+}
+
+uint32_t dal_get_connected_targets_vector(struct dal *dal)
+{
+ struct topology_mgr *tm_mgr;
+ uint32_t connected_displays;
+ uint32_t ind;
+ uint32_t disp_path_num;
+ struct display_path *disp_path;
+
+ /* For DAL disabled support, report 1 pipe for fake display */
+ if (dal == NULL)
+ return 1;
+
+ tm_mgr = dal->topology_mgr;
+
+ disp_path_num = dal_tm_get_num_display_paths(tm_mgr, false);
+
+ connected_displays = 0;
+
+ for (ind = 0; ind < disp_path_num; ind++) {
+ disp_path = dal_tm_display_index_to_display_path(tm_mgr, ind);
+
+ if (dal_display_path_is_target_connected(disp_path))
+ connected_displays |= (1 << ind);
+ } /* for() */
+
+ return connected_displays;
+}
+
+uint32_t dal_get_cofunctional_targets_number(struct dal *dal)
+{
+ struct dal_context *dal_context = &dal->dal_context;
+
+ DAL_IF_TRACE();
+
+ return dal_tm_max_num_cofunctional_targets(dal->topology_mgr);
+}
+
+/* Return a bitvector of *all* Display Paths. */
+uint32_t dal_get_supported_displays_vector(struct dal *dal)
+{
+ uint32_t disp_path_num;
+ uint32_t supported_disp = 0;
+ uint32_t ind;
+
+ /* For DAL disabled support, report 1 pipe for fake display */
+ if (dal == NULL)
+ return 1;
+
+ disp_path_num = dal_tm_get_num_display_paths(dal->topology_mgr,
+ false);
+
+ for (ind = 0; ind < disp_path_num; ind++)
+ supported_disp |= dal_get_display_vector_by_index(dal, ind);
+
+ return supported_disp;
+}
+
+uint32_t dal_get_a_display_index_by_type(struct dal *dal,
+ uint32_t display_type)
+{
+ struct dal_context *dal_context = &dal->dal_context;
+
+ DAL_IF_NOT_IMPLEMENTED();
+
+ /* TODO */
+ return 0;
+}
+
+enum signal_type dal_get_display_signal(
+ struct dal *dal,
+ uint32_t display_index)
+{
+ struct display_path *path =
+ dal_tm_display_index_to_display_path(
+ dal->topology_mgr,
+ display_index);
+
+ if (!path)
+ return SIGNAL_TYPE_NONE;
+
+ return dal_display_path_get_active_signal(path, SINK_LINK_INDEX);
+}
+
+const uint8_t *dal_get_display_edid(
+ struct dal *dal,
+ uint32_t display_index,
+ uint32_t *buff_size)
+{
+ struct dcs *dcs;
+ struct display_path *path =
+ dal_tm_display_index_to_display_path(
+ dal->topology_mgr,
+ display_index);
+
+ if (!path)
+ return NULL;
+
+ dcs = dal_display_path_get_dcs(path);
+
+ if (!dcs)
+ return NULL;
+
+ return dal_dcs_get_edid_raw_data(dcs, buff_size);
+}
+
+void dal_get_screen_info(
+ struct dal *dal,
+ uint32_t display_index,
+ struct edid_screen_info *screen_info)
+{
+ struct dcs *dcs;
+ struct display_path *path =
+ dal_tm_display_index_to_display_path(
+ dal->topology_mgr,
+ display_index);
+
+ if (!screen_info)
+ return;
+
+ if (!path)
+ return;
+
+ dcs = dal_display_path_get_dcs(path);
+
+ if (!dcs)
+ return;
+
+ dal_dcs_get_screen_info(dcs, screen_info);
+}
+
+uint32_t dal_get_display_vector_by_index(struct dal *dal,
+ uint32_t display_index)
+{
+ uint32_t disp_path_num = 0;
+ uint32_t return_val;
+
+ disp_path_num = dal_tm_get_num_display_paths(dal->topology_mgr, false);
+
+ if (display_index >= disp_path_num)
+ return_val = 0;
+ else
+ return_val = (1 << display_index);
+
+ return return_val;
+}
+
+/* TODO: implement later
+bool dal_get_display_output_descriptor (struct dal *dal,
+ uint32_t display_index,
+ struct dal_display_output_descriptor *display_descriptor);
+*/
+
+void dal_pin_active_path_modes(
+ struct dal *dal,
+ void *param,
+ uint32_t display_index,
+ void (*func)(void *, const struct path_mode *))
+{
+ struct ds_dispatch *ds_dispatch;
+ struct dal_context *dal_context = &dal->dal_context;
+
+ DAL_IF_TRACE();
+
+ ds_dispatch = dal_display_service_get_set_mode_interface(
+ dal->display_service);
+
+ if (NULL == ds_dispatch) {
+ DAL_IF_ERROR("%s: DS Dispatch Interface is NULL!\n", __func__);
+ return;
+ }
+
+
+ dal_ds_dispatch_pin_active_path_modes(
+ ds_dispatch,
+ param,
+ display_index,
+ func);
+}
+
+static void dump_path_mode(struct dal *dal,
+ uint32_t pm_num,
+ const struct path_mode *pm)
+{
+ struct dal_context *dal_context = &dal->dal_context;
+
+ dal_logger_write(dal_context->logger, LOG_MAJOR_INTERFACE_TRACE,
+ LOG_MINOR_COMPONENT_DAL_INTERFACE,
+ "PM[%02d]: PathIndex=%02d: view.height: %d, view.width: %d\n",
+ pm_num, pm->display_path_index,
+ pm->view.height, pm->view.width);
+}
+
+static void dump_path_mode_set(struct dal *dal,
+ const struct path_mode_set *pms)
+{
+ uint32_t i;
+ struct dal_context *dal_context = &dal->dal_context;
+
+ if (false == dal_logger_should_log(dal_context->logger,
+ LOG_MAJOR_INTERFACE_TRACE,
+ LOG_MINOR_COMPONENT_DAL_INTERFACE))
+ return;
+
+ dal_logger_write(dal_context->logger, LOG_MAJOR_INTERFACE_TRACE,
+ LOG_MINOR_COMPONENT_DAL_INTERFACE,
+ "SetMode: Number of Path Modes in Set: %d\n", pms->count);
+
+ for (i = 0; i < pms->count; i++)
+ dump_path_mode(dal, i, &pms->path_mode_set[i]);
+}
+
+/* Mode Set */
+bool dal_set_path_mode(struct dal *dal,
+ const struct path_mode_set *pms)
+{
+ struct ds_dispatch *ds_dispatch;
+ struct dal_context *dal_context = &dal->dal_context;
+
+ ds_dispatch =
+ dal_display_service_get_set_mode_interface(
+ dal->display_service);
+
+ if (!ds_dispatch)
+ return false;
+
+ dump_path_mode_set(dal, pms);
+
+ if (DS_SUCCESS == dal_ds_dispatch_set_mode(ds_dispatch, pms))
+ return true;
+
+ DAL_IF_ERROR(
+ "%s: dal_set_mode_interface_set_mode() failed!\n",
+ __func__);
+
+ return false;
+}
+
+bool dal_reset_path_mode(struct dal *dal,
+ const uint32_t displays_num,
+ const uint32_t *display_indexes)
+{
+ struct ds_dispatch *ds_dispatch;
+ struct dal_context *dal_context = &dal->dal_context;
+
+ ds_dispatch =
+ dal_display_service_get_reset_mode_interface(
+ dal->display_service);
+
+ if (!ds_dispatch)
+ return false;
+
+ if (DS_SUCCESS == dal_ds_dispatch_reset_mode(ds_dispatch,
+ displays_num, display_indexes))
+ return true;
+
+ DAL_IF_ERROR(
+ "%s: dal_ds_dispatch_reset_mode() failed!\n",
+ __func__);
+
+ return false;
+}
+
+/* PowerPlay */
+
+bool dal_pre_adapter_clock_change(struct dal *dal,
+ struct power_to_dal_info *clks_info)
+{
+ if (dal_adapter_service_is_feature_supported(
+ FEATURE_USE_PPLIB)) {
+ struct dal_context *dal_context = &dal->dal_context;
+ struct ds_dispatch *ds_dispatch;
+ struct gpu *gpu = NULL;
+ enum ds_return result;
+ struct gpu_clock_info gpu_clk_info;
+
+ ds_dispatch = dal_display_service_get_set_mode_interface(
+ dal->display_service);
+
+ if (NULL == ds_dispatch) {
+ DAL_IF_ERROR("%s: Display Service is NULL!\n",
+ __func__);
+ return false;
+ }
+
+ result = dal_ds_dispatch_pre_adapter_clock_change(ds_dispatch);
+
+ /* cache new clock values, to be applied when
+ * post_adapter_clock_change is called
+ */
+ gpu_clk_info.min_sclk_khz = clks_info->min_sclk;
+ gpu_clk_info.max_sclk_khz = clks_info->max_sclk;
+ gpu_clk_info.min_mclk_khz = clks_info->min_mclk;
+ gpu_clk_info.max_mclk_khz = clks_info->max_mclk;
+
+ gpu = dal_tm_get_gpu(dal->topology_mgr);
+
+ dal_gpu_update_dynamic_clock_info(gpu, &gpu_clk_info);
+
+ if (result == DS_SUCCESS)
+ return true;
+
+ }
+
+ return false;
+}
+
+bool dal_post_adapter_clock_change(struct dal *dal)
+{
+ /* Up to this point we are using 'safe' marks, which are not
+ * power-efficient.
+ * Program stutter and other display marks to values provided
+ * by PPLib. */
+ if (dal_adapter_service_is_feature_supported(
+ FEATURE_USE_PPLIB)) {
+
+ struct dal_context *dal_context = &dal->dal_context;
+ struct ds_dispatch *ds_dispatch;
+ enum ds_return result;
+
+ ds_dispatch = dal_display_service_get_set_mode_interface(
+ dal->display_service);
+
+ if (NULL == ds_dispatch) {
+ DAL_IF_ERROR("%s: Display Service is NULL!\n",
+ __func__);
+ return false;
+ }
+
+ result = dal_ds_dispatch_post_adapter_clock_change(ds_dispatch);
+
+ if (result == DS_SUCCESS)
+ return true;
+ }
+
+ return false;
+}
+
+/* Power Control */
+void dal_set_display_dpms(
+ struct dal *dal,
+ uint32_t display_index,
+ enum dal_power_state state)
+{
+ switch (state) {
+ case DAL_POWER_STATE_ON:
+ dal_display_service_target_power_control(
+ dal->display_service,
+ display_index, true);
+ break;
+ case DAL_POWER_STATE_STANDBY:
+ case DAL_POWER_STATE_SUSPEND:
+ case DAL_POWER_STATE_OFF:
+ dal_display_service_mem_request_control(
+ dal->display_service,
+ display_index,
+ false);
+
+ dal_display_service_target_power_control(
+ dal->display_service,
+ display_index, false);
+ break;
+ default:
+ break;
+ }
+
+}
+
+void dal_set_power_state(
+ struct dal *dal,
+ enum dal_acpi_cm_power_state power_state,
+ enum dal_video_power_state video_power_state)
+{
+ dal_tm_set_current_power_state(
+ dal->topology_mgr, video_power_state);
+ switch (power_state) {
+ case DAL_ACPI_CM_POWER_STATE_D0:
+ /*TODO:NotifyMultiDisplayConfig*/
+ dal_tm_init_hw(dal->topology_mgr);
+ break;
+ default:
+ /*TODO: Synchronization code goes here*/
+ dal_tm_power_down_hw(dal->topology_mgr);
+ break;
+ }
+
+}
+
+void dal_set_blanking(struct dal *dal, uint32_t display_index, bool blank)
+{
+ struct dal_context *dal_context = &dal->dal_context;
+
+ DAL_IF_TRACE();
+
+ /* Return value is not checked here because dal_set_blanking could
+ * be called while HW is not ready for programming (i.e. on boot up) */
+ dal_display_service_mem_request_control(dal->display_service,
+ display_index, blank);
+}
+
+void dal_shut_down_display_block(struct dal *dal)
+{
+ struct dal_context *dal_context = &dal->dal_context;
+
+ DAL_IF_NOT_IMPLEMENTED();
+ /* TODO */
+}
+
+/* Brightness Interface */
+bool dal_set_backlight_level(
+ struct dal *dal,
+ uint32_t display_index,
+ uint32_t brightness)
+{
+ struct ds_dispatch *ds_dispatch =
+ dal_display_service_get_adjustment_interface(
+ dal->display_service);
+ enum ds_return result;
+
+ if (dal_tm_get_embedded_device_index(dal->topology_mgr) !=
+ display_index)
+ return false;
+
+ if (!ds_dispatch)
+ return NULL;
+
+ result =
+ dal_ds_dispatch_set_adjustment(
+ ds_dispatch,
+ display_index,
+ ADJ_ID_BACKLIGHT,
+ brightness);
+
+ return result == DS_SUCCESS;
+}
+
+bool dal_get_backlight_level_old(
+ struct dal *dal,
+ uint32_t display_index,
+ void *adjustment)
+{
+ struct dal_context *dal_context = &dal->dal_context;
+
+ DAL_IF_NOT_IMPLEMENTED();
+ /* TODO */
+ return 0;
+}
+
+bool dal_backlight_control_on(struct dal *dal)
+{
+ struct dal_context *dal_context = &dal->dal_context;
+
+ DAL_IF_NOT_IMPLEMENTED();
+ /* TODO */
+ return 0;
+}
+
+bool dal_backlight_control_off(struct dal *dal)
+{
+ struct dal_context *dal_context = &dal->dal_context;
+
+ DAL_IF_NOT_IMPLEMENTED();
+ /* TODO */
+ return 0;
+}
+
+/* Brightness and color Control */
+void dal_set_palette(struct dal *dal,
+ uint32_t display_index,
+ struct dal_dev_c_lut palette,
+ uint32_t start,
+ uint32_t length)
+{
+ struct dal_context *dal_context = &dal->dal_context;
+
+ DAL_IF_NOT_IMPLEMENTED();
+ /* TODO */
+}
+
+bool dal_set_gamma(
+ struct dal *dal,
+ uint32_t display_index,
+ struct raw_gamma_ramp *gamma)
+{
+ enum ds_return result;
+ struct dal_context *dal_context = &dal->dal_context;
+ struct ds_dispatch *ds_dispatch =
+ dal_display_service_get_adjustment_interface(
+ dal->display_service);
+
+ if (NULL == ds_dispatch) {
+ DAL_IF_ERROR("%s: Display Service is NULL!\n",
+ __func__);
+ return false;
+ }
+
+ result = dal_ds_dispatch_set_gamma_adjustment(
+ ds_dispatch,
+ display_index,
+ ADJ_ID_GAMMA_RAMP,
+ gamma);
+
+ return result == DS_SUCCESS;
+}
+
+/* Active Stereo Interface */
+bool dal_control_stereo(struct dal *dal,
+ uint32_t display_index,
+ bool enable)
+{
+ struct dal_context *dal_context = &dal->dal_context;
+
+ DAL_IF_NOT_IMPLEMENTED();
+ /* TODO */
+ return 0;
+}
+
+/* Disable All DC Pipes - blank CRTC and disable memory requests */
+void dal_disable_all_dc_pipes(struct dal *dal)
+{
+ struct dal_context *dal_context = &dal->dal_context;
+
+ DAL_IF_NOT_IMPLEMENTED();
+ /* TODO */
+}
+
+/******************************************************************************
+ Timing List Query
+******************************************************************************/
+struct dal_timing_list_query *dal_create_timing_list_query(struct dal *dal,
+ uint32_t display_index)
+{
+ struct display_path *display_path;
+ struct timing_list_query_init_data init_data = { 0 };
+ struct dal_timing_list_query *tlsq;
+ struct dal_context *dal_context = &dal->dal_context;
+
+ display_path = dal_tm_display_index_to_display_path(dal->topology_mgr,
+ display_index);
+ if (!display_path) {
+ DAL_IF_ERROR(
+ "%s: dal_tm_display_index_to_display_path() failed!\n",
+ __func__);
+ return NULL;
+ }
+
+ init_data.dal = dal;
+ init_data.dcs = dal_display_path_get_dcs(display_path);
+ init_data.timing_srv = dal->timing_srv;
+ init_data.display_index = display_index;
+
+ tlsq = dal_timing_list_query_create(&init_data);
+ if (!tlsq) {
+ DAL_IF_ERROR("%s: timing_list_query_create() failed!\n",
+ __func__);
+ return NULL;
+ }
+
+ return tlsq;
+}
+
+/*****************************************************************************
+ Implementation of private functions.
+ *****************************************************************************/
+static struct adapter_service *create_as(struct dal *dal)
+{
+ struct adapter_service *as = NULL;
+ struct as_init_data init_data;
+ struct dal_init_data *init = &dal->init_data;
+
+ dal_memset(&init_data, 0, sizeof(init_data));
+
+ init_data.dal_context = &dal->dal_context;
+
+ /* BIOS parser init data */
+ init_data.bp_init_data.dal_context = &dal->dal_context;
+ init_data.bp_init_data.bios = init->asic_id.atombios_base_address;
+
+ /* HW init data */
+ init_data.hw_init_data.chip_family = init->asic_id.chip_family;
+ init_data.hw_init_data.chip_id = init->asic_id.chip_id;
+ init_data.hw_init_data.fake_paths_num = init->asic_id.fake_paths_num;
+ init_data.hw_init_data.feature_flags = init->asic_id.feature_flags;
+ init_data.hw_init_data.hw_internal_rev = init->asic_id.hw_internal_rev;
+ init_data.hw_init_data.runtime_flags = init->asic_id.runtime_flags;
+ init_data.hw_init_data.vram_width = init->asic_id.vram_width;
+ init_data.hw_init_data.vram_type = init->asic_id.vram_type;
+
+ /* bdf is BUS,DEVICE,FUNCTION*/
+ init_data.bdf_info = init->bdf_info;
+
+ init_data.display_param = &init->display_param;
+
+ as = dal_adapter_service_create(&init_data);
+
+ return as;
+}
+
+/*hard code color square at CRTC0 for HDMI light up*/
+void dal_set_crtc_test_pattern(struct dal *dal)
+{
+ struct topology_mgr *tm = dal->topology_mgr;
+ struct display_path *dp = dal_tm_display_index_to_display_path(
+ tm, 0);
+ struct controller *crtc = NULL;
+
+ if (dal_display_path_is_acquired(dp))
+ crtc = dal_display_path_get_controller(dp);
+
+ if (crtc != NULL)
+ dal_controller_set_test_pattern(
+ crtc,
+ DP_TEST_PATTERN_COLOR_SQUARES,
+ HW_COLOR_DEPTH_888);
+}
+
+uint32_t dal_get_display_index_from_int_src(struct dal *dal,
+ enum dal_irq_source src)
+{
+ enum controller_id crtc_id;
+
+ /* check if DAL is disabled */
+ if (dal == NULL)
+ return INVALID_DISPLAY_INDEX;
+
+ /* the assumption here is that INT_Y int was generated by
+ CRTC_Y hardware block. That might not be true in the future
+ TODO: greate CRTC to IRQ SRC tables */
+ switch (src) {
+ case DAL_IRQ_SOURCE_CRTC1VSYNC:
+ case DAL_IRQ_SOURCE_CRTC2VSYNC:
+ case DAL_IRQ_SOURCE_CRTC3VSYNC:
+ case DAL_IRQ_SOURCE_CRTC4VSYNC:
+ case DAL_IRQ_SOURCE_CRTC5VSYNC:
+ case DAL_IRQ_SOURCE_CRTC6VSYNC:
+ /*TODO: should we add one for Underlay? */
+ crtc_id = src - DAL_IRQ_SOURCE_CRTC1VSYNC + 1;
+ break;
+ case DAL_IRQ_SOURCE_PFLIP1:
+ case DAL_IRQ_SOURCE_PFLIP2:
+ case DAL_IRQ_SOURCE_PFLIP3:
+ case DAL_IRQ_SOURCE_PFLIP4:
+ case DAL_IRQ_SOURCE_PFLIP5:
+ case DAL_IRQ_SOURCE_PFLIP6:
+ case DAL_IRQ_SOURCE_PFLIP_UNDERLAY0:
+ crtc_id = src - DAL_IRQ_SOURCE_PFLIP1 + 1;
+ break;
+ default:
+ dal_logger_write(dal->dal_context.logger,
+ LOG_MAJOR_ERROR, LOG_MINOR_COMPONENT_ISR,
+ "Unhandled interrupt source %d\n", src);
+ return INVALID_DISPLAY_INDEX;
+ }
+
+ return dal_tm_get_display_path_index_for_controller(
+ dal->topology_mgr,
+ crtc_id);
+}
+
+/* return crtc scanout v/h counter, return if inside v_blank*/
+uint32_t dal_get_crtc_scanoutpos(
+ struct dal *dal,
+ uint32_t display_index,
+ int32_t *vpos,
+ int32_t *hpos)
+{
+ struct topology_mgr *tm = dal->topology_mgr;
+ struct display_path *dp = dal_tm_display_index_to_display_path(
+ tm, display_index);
+ struct controller *cont = dal_display_path_get_controller(dp);
+
+ if (!cont) {
+ dal_logger_write(dal->dal_context.logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DAL_INTERFACE,
+ "Failed to find controller at display index %d\n",
+ display_index);
+ return 0;
+ }
+
+ return dal_controller_get_crtc_scanoutpos(cont, vpos, hpos);
+
+}
+
+static enum dal_irq_source get_irq_src_from_display_index_helper(
+ struct dal *dal,
+ uint32_t display_index,
+ uint32_t plane_no,
+ enum dal_irq_source base_irq_source)
+{
+ struct display_path *display_path;
+ struct controller *controller;
+ enum controller_id crtc_id;
+ enum dal_irq_source src;
+
+ /* return base irq source in DAL bypass mode */
+ if (dal == NULL)
+ return base_irq_source;
+
+ display_path = dal_tm_display_index_to_display_path(dal->topology_mgr,
+ display_index);
+
+ controller = dal_display_path_get_controller_for_layer_index(
+ display_path, plane_no);
+
+ if (NULL == controller)
+ return DAL_IRQ_SOURCE_INVALID;
+
+ crtc_id = dal_controller_get_graphics_object_id(controller).id;
+
+ src = crtc_id - 1 + base_irq_source;
+
+ return src;
+}
+
+enum dal_irq_source dal_get_vblank_irq_src_from_display_index(
+ struct dal *dal,
+ uint32_t display_index)
+{
+ return get_irq_src_from_display_index_helper(
+ dal,
+ display_index,
+ 0,
+ DAL_IRQ_SOURCE_CRTC1VSYNC);
+}
+
+void dal_set_vblank_irq(
+ struct dal *dal,
+ uint32_t display_index,
+ bool enable)
+{
+ struct display_path *display_path;
+ struct controller *controller;
+ struct line_buffer *lb;
+
+ display_path = dal_tm_display_index_to_display_path(dal->topology_mgr,
+ display_index);
+
+ controller = dal_tm_get_controller_from_display_path(dal->topology_mgr,
+ display_path);
+
+ if (NULL == controller)
+ return;
+
+ lb = dal_controller_get_line_buffer(controller);
+ if (NULL == lb)
+ return;
+ dal_line_buffer_set_vblank_irq(lb, enable);
+}
+
+enum dal_irq_source dal_get_pflip_irq_src_from_display_index(
+ struct dal *dal,
+ uint32_t display_index,
+ uint32_t plane_no)
+{
+ return get_irq_src_from_display_index_helper(
+ dal,
+ display_index,
+ plane_no,
+ DAL_IRQ_SOURCE_PFLIP1);
+}
+
+struct is_display_active_param {
+ bool active;
+ uint32_t display_index;
+};
+
+struct mode_manager *dal_get_mode_manager(struct dal *dal)
+{
+ return dal->mm;
+}
+
+struct mode_query *dal_get_mode_query(
+ struct dal *dal,
+ struct topology *tp,
+ enum query_option query_option)
+{
+ return dal_mode_manager_create_mode_query(dal->mm, tp, query_option);
+}
+
+
+/* DSAT Accessors, definition is in dsat.c */
+struct topology_mgr *dal_get_tm(struct dal *dal)
+{
+ return dal->topology_mgr;
+}
+
+struct adapter_service *dal_get_as(struct dal *dal)
+{
+ return dal->adapter_srv;
+}
+
+struct timing_service *dal_get_ts(struct dal *dal)
+{
+ return dal->timing_srv;
+}
+
+struct hw_sequencer *dal_get_hws(struct dal *dal)
+{
+ return dal->hws;
+}
+
+struct display_service *dal_get_ds(struct dal *dal)
+{
+ return dal->display_service;
+}
+
+struct mode_manager *dal_get_mm(struct dal *dal)
+{
+ return dal->mm;
+}
+
+struct dal_context *dal_get_dal_ctx(struct dal *dal)
+{
+ return &dal->dal_context;
+}
+
+struct dal_init_data *dal_get_init_data(struct dal *dal)
+{
+ return &dal->init_data;
+}
+
+bool dal_set_cursor_position(
+ struct dal *dal,
+ const uint32_t display_index,
+ const struct cursor_position *position
+ )
+{
+ struct display_path *dp_path;
+
+ if (!position)
+ return false;
+
+ dp_path =
+ dal_tm_display_index_to_display_path(
+ dal->topology_mgr,
+ display_index);
+
+ return dal_hw_sequencer_set_cursor_position(
+ dal->hws,
+ dp_path,
+ position);
+}
+
+bool dal_set_cursor_attributes(
+ struct dal *dal,
+ const uint32_t display_index,
+ const struct cursor_attributes *attributes
+ )
+{
+ struct display_path *dp_path;
+
+ if (!attributes)
+ return false;
+
+ dp_path =
+ dal_tm_display_index_to_display_path(
+ dal->topology_mgr,
+ display_index);
+
+ return dal_hw_sequencer_set_cursor_attributes(
+ dal->hws,
+ dp_path,
+ attributes);
+}
+
+
+static enum pixel_format convert_pixel_format_plane_to_dalsurface(
+ enum surface_pixel_format surface_pixel_format)
+{
+ enum pixel_format dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
+
+ switch (surface_pixel_format) {
+ case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
+ dal_pixel_format = PIXEL_FORMAT_INDEX8;
+ break;
+ case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
+ dal_pixel_format = PIXEL_FORMAT_RGB565;
+ break;
+ case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
+ dal_pixel_format = PIXEL_FORMAT_RGB565;
+ break;
+ case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
+ dal_pixel_format = PIXEL_FORMAT_ARGB8888;
+ break;
+ case SURFACE_PIXEL_FORMAT_GRPH_BGRA8888:
+ dal_pixel_format = PIXEL_FORMAT_ARGB8888;
+ break;
+ case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
+ dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
+ break;
+ case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
+ dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
+ break;
+ case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
+ dal_pixel_format = PIXEL_FORMAT_ARGB2101010_XRBIAS;
+ break;
+ case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
+ dal_pixel_format = PIXEL_FORMAT_FP16;
+ break;
+ case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
+ dal_pixel_format = PIXEL_FORMAT_FP16;
+ break;
+
+
+ case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
+ dal_pixel_format = PIXEL_FORMAT_420BPP12;
+ break;
+ case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
+ dal_pixel_format = PIXEL_FORMAT_420BPP12;
+ break;
+ case SURFACE_PIXEL_FORMAT_VIDEO_422_YCb:
+ dal_pixel_format = PIXEL_FORMAT_422BPP16;
+ break;
+ case SURFACE_PIXEL_FORMAT_VIDEO_422_YCr:
+ dal_pixel_format = PIXEL_FORMAT_422BPP16;
+ break;
+ case SURFACE_PIXEL_FORMAT_VIDEO_422_CbY:
+ dal_pixel_format = PIXEL_FORMAT_422BPP16;
+ break;
+ case SURFACE_PIXEL_FORMAT_VIDEO_422_CrY:
+ dal_pixel_format = PIXEL_FORMAT_422BPP16;
+ break;
+ case SURFACE_PIXEL_FORMAT_VIDEO_444_ACrYCb1555:
+ dal_pixel_format = PIXEL_FORMAT_444BPP16;
+ break;
+ case SURFACE_PIXEL_FORMAT_VIDEO_444_CrYCb565:
+ dal_pixel_format = PIXEL_FORMAT_444BPP16;
+ break;
+ case SURFACE_PIXEL_FORMAT_VIDEO_444_ACrYCb4444:
+ dal_pixel_format = PIXEL_FORMAT_444BPP16;
+ break;
+ case SURFACE_PIXEL_FORMAT_VIDEO_444_CbYCrA5551:
+ dal_pixel_format = PIXEL_FORMAT_444BPP16;
+ break;
+ case SURFACE_PIXEL_FORMAT_VIDEO_444_ACrYCb8888:
+ dal_pixel_format = PIXEL_FORMAT_444BPP32;
+ break;
+ case SURFACE_PIXEL_FORMAT_VIDEO_444_ACrYCb2101010:
+ dal_pixel_format = PIXEL_FORMAT_444BPP32;
+ break;
+ case SURFACE_PIXEL_FORMAT_VIDEO_444_CbYCrA1010102:
+ dal_pixel_format = PIXEL_FORMAT_444BPP32;
+ break;
+ default:
+ dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
+ break;
+ }
+ return dal_pixel_format;
+}
+
+bool dal_validate_plane_configurations(struct dal *dal,
+ int num_planes,
+ const struct plane_config *pl_config,
+ bool *supported)
+{
+ struct ds_dispatch *ds_dispatch =
+ dal_display_service_get_set_mode_interface(
+ dal->display_service);
+
+ if (NULL == ds_dispatch) {
+ struct dal_context *dal_context = &dal->dal_context;
+
+ DAL_IF_ERROR(
+ "%s: ds_dispatch is NULL!\n",
+ __func__);
+
+ return false;
+ }
+
+ if (dal_ds_dispatch_validate_plane_configurations(
+ ds_dispatch,
+ num_planes,
+ pl_config,
+ supported))
+ return true;
+
+ return false;
+}
+
+/*TODO fill struct plane_attributes attributes;
+ * for scaler*/
+bool dal_setup_plane_configurations(
+ struct dal *dal,
+ uint32_t num_planes,
+ struct plane_config *configs)
+{
+ struct dal_context *dal_context = &dal->dal_context;
+ struct ds_dispatch *ds_dispatch;
+ uint32_t display_index = configs[0].display_index;
+ uint32_t i = 0;
+
+ if (configs == NULL)
+ return false;
+
+ if (num_planes == 0 || num_planes > MAX_PLANE_NUM)
+ return false;
+
+ ds_dispatch =
+ dal_display_service_get_set_mode_interface(
+ dal->display_service);
+
+ if (!ds_dispatch) {
+ DAL_IF_ERROR("%s: ds_dispatch is NULL!\n", __func__);
+ return false;
+ }
+
+ /*convert dm surface pixel format into DAL internal surface format*/
+ for (i = 0; i < num_planes; i++) {
+ configs[i].config.dal_pixel_format =
+ convert_pixel_format_plane_to_dalsurface(
+ configs[i].config.format);
+ }
+
+ dal_ds_dispatch_setup_plane_configurations(
+ ds_dispatch,
+ display_index,
+ num_planes,
+ configs);
+
+ return true;
+}
+
+bool dal_update_plane_addresses(
+ struct dal *dal,
+ uint32_t num_planes,
+ struct plane_addr_flip_info *info)
+{
+ struct display_path *dp_path;
+
+ if (num_planes == 0 || num_planes > MAX_PLANE_NUM)
+ return false;
+
+ if (!info)
+ return false;
+
+ dp_path =
+ dal_tm_display_index_to_display_path(
+ dal->topology_mgr,
+ info[0].display_index);
+
+ return dal_hw_sequencer_update_plane_address(
+ dal->hws,
+ dp_path,
+ num_planes,
+ info);
+}
+
+static bool remote_display_receiver_caps_set(
+ struct dal *dal,
+ struct display_path *disp_path,
+ struct dal_remote_display_receiver_capability *caps)
+{
+ struct dcs *dcs;
+
+ dcs = dal_display_path_get_dcs(disp_path);
+ if (NULL == dcs) {
+ dal_logger_write(dal->dal_context.logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DAL_INTERFACE,
+ "%s: DCS is NULL!\n", __func__);
+ return false;
+ }
+
+ dal_dcs_set_remote_display_receiver_capabilities(dcs, caps);
+
+ return true;
+}
+
+uint32_t dal_wifi_display_acquire(
+ struct dal *dal,
+ uint8_t *edid_data,
+ uint32_t edid_size,
+ struct dal_remote_display_receiver_capability *caps,
+ uint32_t *display_index)
+{
+ struct display_path *disp_path = NULL;
+
+ if (edid_data == NULL || caps == NULL) {
+ ASSERT_CRITICAL(0);
+ dal_logger_write(dal->dal_context.logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DAL_INTERFACE,
+ "Wifi display capability is NULL");
+ /*TODO: define an enum for error codes
+ * and make this function return that enum
+ */
+ return -1;
+ }
+
+ *display_index = dal_tm_get_wireless_display_index(
+ dal->topology_mgr);
+
+ if (*display_index == INVALID_DISPLAY_INDEX) {
+ ASSERT_CRITICAL(0);
+ dal_logger_write(dal->dal_context.logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DAL_INTERFACE,
+ "Wireless display index is invalid");
+ return -1;
+ }
+
+ disp_path = dal_tm_display_index_to_display_path(
+ dal->topology_mgr, *display_index);
+
+ if (disp_path == NULL)
+ return -1;
+
+ if (dal_display_path_is_target_connected(disp_path)) {
+ dal_logger_write(dal->dal_context.logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DAL_INTERFACE,
+ "%s: Failed to acquire disp path - already in use\n",
+ __func__);
+ return -1;
+ }
+
+ if (false == remote_display_receiver_caps_set(dal, disp_path, caps)) {
+ dal_logger_write(dal->dal_context.logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DAL_INTERFACE,
+ "%s: Failed to set remote display caps!\n", __func__);
+ return -1;
+ }
+
+ dal_tm_update_display_edid(
+ dal->topology_mgr, *display_index,
+ edid_data, edid_size);
+
+ dal_tm_set_force_connected(
+ dal->topology_mgr,
+ *display_index,
+ true);
+
+ return 0;
+}
+
+static void remote_display_receiver_caps_clear(
+ struct dal *dal,
+ struct display_path *disp_path)
+{
+ struct dcs *dcs = dal_display_path_get_dcs(disp_path);
+
+ if (NULL == dcs) {
+ dal_logger_write(dal->dal_context.logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DAL_INTERFACE,
+ "%s: DCS is NULL!\n", __func__);
+ return;
+ }
+
+ dal_dcs_clear_remote_display_receiver_capabilities(dcs);
+}
+
+uint32_t dal_wifi_display_release(
+ struct dal *dal,
+ uint32_t *display_index)
+{
+ struct display_path *disp_path = NULL;
+
+ *display_index = dal_tm_get_wireless_display_index(
+ dal->topology_mgr);
+
+ if (*display_index == INVALID_DISPLAY_INDEX) {
+ ASSERT_CRITICAL(0);
+ dal_logger_write(dal->dal_context.logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DAL_INTERFACE,
+ "Wireless display index is invalid");
+ return -1;
+ }
+
+ disp_path = dal_tm_display_index_to_display_path(
+ dal->topology_mgr, *display_index);
+
+ if (false == dal_display_path_is_target_connected(disp_path)) {
+ dal_logger_write(dal->dal_context.logger,
+ LOG_MAJOR_ERROR,
+ LOG_MINOR_COMPONENT_DAL_INTERFACE,
+ "Display path is not connected, display path probably not acquired");
+ return -1;
+ }
+
+ dal_tm_set_force_connected(
+ dal->topology_mgr,
+ *display_index,
+ false);
+
+ remote_display_receiver_caps_clear(dal, disp_path);
+
+ return 0;
+}
+
+/*
+ * dal_get_vblank_counter
+ *
+ * @brief
+ * Get the current vertical blank counts for given CRTC.
+ *
+ * @param
+ * struct dal *dal - [in] DAL instance
+ * int disp_idx - [in] display index
+ *
+ * @return
+ * Return the CRTC counter for frame
+ */
+uint32_t dal_get_vblank_counter(struct dal *dal, int disp_idx)
+{
+ struct topology_mgr *tm = dal->topology_mgr;
+ struct display_path *dp = dal_tm_display_index_to_display_path(
+ tm, disp_idx);
+ struct controller *cont = NULL;
+
+ if (dal_display_path_is_acquired(dp))
+ cont = dal_display_path_get_controller(dp);
+ else
+ return 0;
+
+ return dal_controller_get_vblank_counter(cont);
+}
+
+void dal_interrupt_set(struct dal *dal, enum dal_irq_source src, bool enable)
+{
+ dal_irq_service_set(dal->irqs, src, enable);
+}
+
+void dal_interrupt_ack(struct dal *dal, enum dal_irq_source src)
+{
+ dal_irq_service_ack(dal->irqs, src);
+}
+
+enum dal_irq_source dal_interrupt_to_irq_source(
+ struct dal *dal,
+ uint32_t src_id,
+ uint32_t ext_id)
+{
+ return dal_irq_service_to_irq_source(dal->irqs, src_id, ext_id);
+}
diff --git a/drivers/gpu/drm/amd/dal/interface/timing_list_query.c b/drivers/gpu/drm/amd/dal/interface/timing_list_query.c
new file mode 100644
index 000000000000..bb5c044f03e0
--- /dev/null
+++ b/drivers/gpu/drm/amd/dal/interface/timing_list_query.c
@@ -0,0 +1,371 @@
+/* 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_list_query_interface.h"
+#include "include/timing_service_interface.h"
+#include "include/mode_timing_list_interface.h"
+#include "include/mode_manager_interface.h"
+#include "include/dal_interface.h"
+
+struct dal_timing_list_query {
+ /* instance of DAL which created this query */
+ struct dal *parent_dal;
+ struct timing_service *timing_srv;
+ struct dcs *dcs;
+ uint32_t display_index;
+ /* mode timing list for display_path */
+ struct mode_timing_list *mode_timing_list;
+ uint32_t added_timing_count;
+ struct display_pixel_encoding_support pes;
+
+ /* following var is used for caching. In DAL2 it static variable inside
+ * function. Was decided to refactor it */
+ struct display_color_depth_support cds;
+};
+
+
+/******************************************************************************
+ * Private functions
+ *****************************************************************************/
+
+static bool construct(
+ struct dal_timing_list_query *tlsq,
+ struct timing_list_query_init_data *init_data)
+{
+ tlsq->dcs = init_data->dcs;
+ tlsq->display_index = init_data->display_index;
+ tlsq->parent_dal = init_data->dal;
+ tlsq->timing_srv = init_data->timing_srv;
+
+ tlsq->mode_timing_list =
+ dal_timing_service_get_mode_timing_list_for_path(
+ tlsq->timing_srv,
+ tlsq->display_index);
+
+ return NULL != tlsq->mode_timing_list;
+}
+
+static void destruct(struct dal_timing_list_query *tlsq)
+{
+ if (tlsq->added_timing_count) {
+ dal_mode_manager_update_disp_path_func_view_tbl(
+ dal_get_mode_manager(tlsq->parent_dal),
+ tlsq->display_index,
+ dal_timing_service_get_mode_timing_list_for_path(
+ tlsq->timing_srv,
+ tlsq->display_index));
+
+ dal_timing_service_dump(tlsq->timing_srv,
+ tlsq->display_index);
+ }
+}
+
+/**
+ *****************************************************************************
+ * Function: get_next_display_supported_pixel_encoding()
+ *
+ * helper function to get next supported pixelEncoding from DCS data
+ *
+ * @param [in] update_from_dcs - get from DCS or use cache
+ * @param [in] pe - the specific PixelEncoding
+ *
+ * @return
+ * return true if found
+ *
+ * @note
+ *
+ * @see
+ *
+ *****************************************************************************
+ */
+
+static bool get_next_display_supported_pixel_encoding(
+ struct dal_timing_list_query *tlsq,
+ bool update_from_dcs,
+ enum pixel_encoding pe)
+{
+ bool ret = true;
+ /* TODO: can not complete because of dependency on DCS.
+ * Finish when DCS is ready. */
+ return ret;
+}
+
+/******************************************************************************
+ * Public interface implementation.
+ *****************************************************************************/
+struct dal_timing_list_query *dal_timing_list_query_create(
+ struct timing_list_query_init_data *init_data)
+{
+ struct dal_timing_list_query *tlsq;
+
+ tlsq = dal_alloc(sizeof(*tlsq));
+ if (!tlsq)
+ return NULL;
+
+ if (construct(tlsq, init_data))
+ return tlsq;
+
+ BREAK_TO_DEBUGGER();
+ dal_free(tlsq);
+ return NULL;
+}
+
+void dal_timing_list_query_destroy(struct dal_timing_list_query **tlsq)
+{
+ if (!tlsq || !*tlsq) {
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+
+ destruct(*tlsq);
+
+ dal_free(*tlsq);
+
+ *tlsq = NULL;
+}
+
+/* Get count of mode timings in the list. */
+uint32_t dal_timing_list_query_get_mode_timing_count(
+ const struct dal_timing_list_query *tlsq)
+{
+ if (NULL == tlsq) {
+ /* getting here if OS ignores error in
+ * dal_timing_list_query_create() */
+ BREAK_TO_DEBUGGER();
+ return 0;
+ }
+
+ return dal_mode_timing_list_get_count(tlsq->mode_timing_list);
+}
+
+const struct mode_timing *dal_timing_list_query_get_mode_timing_at_index(
+ const struct dal_timing_list_query *tlsq,
+ uint32_t index)
+{
+ if (NULL == tlsq) {
+ /* getting here if OS ignores error in
+ * dal_timing_list_query_create() */
+ BREAK_TO_DEBUGGER();
+ return NULL;
+ }
+
+ return dal_mode_timing_list_get_timing_at_index(
+ tlsq->mode_timing_list, index);
+}
+
+static enum display_color_depth display_color_depth_from_dcs_color_depth(
+ enum color_depth_index color_depth)
+{
+ switch (color_depth) {
+ case COLOR_DEPTH_INDEX_666:
+ return DISPLAY_COLOR_DEPTH_666;
+ case COLOR_DEPTH_INDEX_888:
+ return DISPLAY_COLOR_DEPTH_888;
+ case COLOR_DEPTH_INDEX_101010:
+ return DISPLAY_COLOR_DEPTH_101010;
+ case COLOR_DEPTH_INDEX_121212:
+ return DISPLAY_COLOR_DEPTH_121212;
+ case COLOR_DEPTH_INDEX_141414:
+ return DISPLAY_COLOR_DEPTH_141414;
+ case COLOR_DEPTH_INDEX_161616:
+ return DISPLAY_COLOR_DEPTH_161616;
+ default:
+ return DISPLAY_COLOR_DEPTH_UNDEFINED;
+ }
+}
+
+static bool get_next_color_depth_from_dcs_support(
+ struct display_color_depth_support *cds,
+ enum display_color_depth current_cd,
+ enum display_color_depth *next_cd)
+{
+ enum color_depth_index i;
+ bool next_bit = (current_cd == DISPLAY_COLOR_DEPTH_UNDEFINED);
+
+ for (i = COLOR_DEPTH_INDEX_666; i < COLOR_DEPTH_INDEX_LAST; i <<= 1) {
+ if ((cds->mask & i) == 0)
+ continue;
+
+ if (next_bit) {
+ *next_cd = display_color_depth_from_dcs_color_depth(i);
+ if (*next_cd > DISPLAY_COLOR_DEPTH_888 &&
+ cds->deep_color_native_res_only)
+ continue;
+
+ return true;
+ }
+
+ /* found current bit */
+ if (current_cd == display_color_depth_from_dcs_color_depth(i))
+ next_bit = true;
+ }
+
+ return false;
+}
+
+static bool get_next_display_supported_color_depth(
+ struct dal_timing_list_query *tlsq,
+ bool update_from_dcs,
+ enum display_color_depth *cd)
+{
+ bool ret = true;
+
+ /* we update the data from DCS on demand
+ * so we can re-use the cached data
+ */
+ if (update_from_dcs) {
+ tlsq->cds.mask = 0;
+ ret = dal_dcs_get_display_color_depth(tlsq->dcs, &tlsq->cds);
+ }
+
+ if (ret)
+ ret = get_next_color_depth_from_dcs_support(
+ &tlsq->cds, *cd, cd);
+
+ return ret;
+}
+
+/**
+ *****************************************************************************
+ * timing_list_query_add_timing() is used to add timing to a target timing
+ * mode list.
+ * In case device disconnected, the previously added modes will stay in
+ * the target mode list until a newly connected device arrival and added
+ * timing will be removed automatically by DAL.
+ *****************************************************************************
+ */
+bool dal_timing_list_query_add_timing(struct dal_timing_list_query *tlsq,
+ const struct crtc_timing *crtc_timing,
+ enum timing_support_level support_level)
+{
+ enum timing_source ts;
+ struct mode_timing mt;
+ /* we use this boolean to track whether we need to ask DCS for
+ * the information */
+ bool query_dcs = true;
+ bool ret;
+
+ /* TODO: for wireless always return false, without adding
+ * the mode timing. */
+
+ /* set proper timing source */
+ if (TIMING_SUPPORT_LEVEL_NOT_GUARANTEED == support_level ||
+ TIMING_SUPPORT_LEVEL_UNDEFINED == support_level) {
+ ts = TIMING_SOURCE_DALINTERFACE_IMPLICIT;
+ } else if (TIMING_SUPPORT_LEVEL_GUARANTEED == support_level ||
+ TIMING_SUPPORT_LEVEL_NATIVE == support_level) {
+ ts = TIMING_SOURCE_DALINTERFACE_EXPLICIT;
+ } else {
+ /* bad input */
+ return false;
+ }
+
+ dal_memset(&mt, 0, sizeof(mt));
+
+ mt.crtc_timing = *crtc_timing;
+ mt.mode_info.timing_source = ts;
+
+ /* call TS helper function to create the 'mt.mode_info' */
+ dal_timing_service_create_mode_info_from_timing(crtc_timing,
+ &mt.mode_info);
+
+ mt.crtc_timing.vic = dal_timing_service_get_video_code_for_timing(
+ tlsq->timing_srv, crtc_timing);
+
+ /* Caller may not be able to provide pixel encoding or colour depth
+ * information. If such case occurs, we need to query DCS for
+ * the support */
+
+ if (mt.crtc_timing.display_color_depth != DISPLAY_COLOR_DEPTH_UNDEFINED
+ && mt.crtc_timing.pixel_encoding
+ != PIXEL_ENCODING_UNDEFINED) {
+ /* all defined, we can go ahead call TS */
+ ret = dal_timing_service_add_mode_timing_to_path(
+ tlsq->timing_srv, tlsq->display_index, &mt);
+ } else if (mt.crtc_timing.display_color_depth
+ != DISPLAY_COLOR_DEPTH_UNDEFINED) {
+ /* mt.crtc_timing.pixel_encoding is NOT defined.
+ * We need to get from DCS the supported pixel encoding. */
+ enum pixel_encoding pe;
+
+ query_dcs = true;
+ pe = PIXEL_ENCODING_UNDEFINED;
+
+ while (get_next_display_supported_pixel_encoding(tlsq,
+ query_dcs, pe)) {
+ mt.crtc_timing.pixel_encoding = pe;
+ query_dcs = false;
+
+ /* call TS to add mode timing */
+ ret = dal_timing_service_add_mode_timing_to_path(
+ tlsq->timing_srv, tlsq->display_index,
+ &mt);
+ }
+ } else {
+ /* both display color depth and pixel encoding not defined
+ * we need to get from DCS the supported
+ */
+ enum pixel_encoding pe = PIXEL_ENCODING_UNDEFINED;
+
+ query_dcs = true;
+ while (get_next_display_supported_pixel_encoding(
+ tlsq,
+ query_dcs,
+ pe)) {
+ enum display_color_depth cd =
+ DISPLAY_COLOR_DEPTH_UNDEFINED;
+ mt.crtc_timing.pixel_encoding = pe;
+ while (get_next_display_supported_color_depth(
+ tlsq, query_dcs, &cd)) {
+ mt.crtc_timing.display_color_depth = cd;
+ query_dcs = false;
+
+ if (dal_timing_service_add_mode_timing_to_path(
+ tlsq->timing_srv,
+ tlsq->display_index,
+ &mt))
+ ret = true;
+ }
+
+ if (query_dcs)
+ /* looks like color depth query failed, no need
+ * to continue */
+ break;
+ }
+ }
+
+ if (ret) {
+ dal_mode_manager_update_disp_path_func_view_tbl(
+ dal_get_mode_manager(tlsq->parent_dal),
+ tlsq->display_index,
+ dal_timing_service_get_mode_timing_list_for_path(
+ tlsq->timing_srv,
+ tlsq->display_index));
+ tlsq->added_timing_count++;
+ }
+
+ return ret;
+}