xref: /dflybsd-src/sys/dev/drm/amd/display/amdgpu_dm/amdgpu_dm.c (revision 789731325bde747251c28a37e0a00ed4efb88c46)
1b843c749SSergey Zigachev /*
2b843c749SSergey Zigachev  * Copyright 2015 Advanced Micro Devices, Inc.
3b843c749SSergey Zigachev  *
4b843c749SSergey Zigachev  * Permission is hereby granted, free of charge, to any person obtaining a
5b843c749SSergey Zigachev  * copy of this software and associated documentation files (the "Software"),
6b843c749SSergey Zigachev  * to deal in the Software without restriction, including without limitation
7b843c749SSergey Zigachev  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b843c749SSergey Zigachev  * and/or sell copies of the Software, and to permit persons to whom the
9b843c749SSergey Zigachev  * Software is furnished to do so, subject to the following conditions:
10b843c749SSergey Zigachev  *
11b843c749SSergey Zigachev  * The above copyright notice and this permission notice shall be included in
12b843c749SSergey Zigachev  * all copies or substantial portions of the Software.
13b843c749SSergey Zigachev  *
14b843c749SSergey Zigachev  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15b843c749SSergey Zigachev  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16b843c749SSergey Zigachev  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17b843c749SSergey Zigachev  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18b843c749SSergey Zigachev  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19b843c749SSergey Zigachev  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20b843c749SSergey Zigachev  * OTHER DEALINGS IN THE SOFTWARE.
21b843c749SSergey Zigachev  *
22b843c749SSergey Zigachev  * Authors: AMD
23b843c749SSergey Zigachev  *
24b843c749SSergey Zigachev  */
25b843c749SSergey Zigachev 
26b843c749SSergey Zigachev #include "dm_services_types.h"
27b843c749SSergey Zigachev #include "dc.h"
28b843c749SSergey Zigachev #include "dc/inc/core_types.h"
29b843c749SSergey Zigachev 
30b843c749SSergey Zigachev #include "vid.h"
31b843c749SSergey Zigachev #include "amdgpu.h"
32b843c749SSergey Zigachev #include "amdgpu_display.h"
33b843c749SSergey Zigachev #include "atom.h"
34b843c749SSergey Zigachev #include "amdgpu_dm.h"
35b843c749SSergey Zigachev #include "amdgpu_pm.h"
36b843c749SSergey Zigachev 
37b843c749SSergey Zigachev #include "amd_shared.h"
38b843c749SSergey Zigachev #include "amdgpu_dm_irq.h"
39b843c749SSergey Zigachev #include "dm_helpers.h"
40b843c749SSergey Zigachev #include "dm_services_types.h"
41b843c749SSergey Zigachev #include "amdgpu_dm_mst_types.h"
42b843c749SSergey Zigachev #if defined(CONFIG_DEBUG_FS)
43b843c749SSergey Zigachev #include "amdgpu_dm_debugfs.h"
44b843c749SSergey Zigachev #endif
45b843c749SSergey Zigachev 
46b843c749SSergey Zigachev #include "ivsrcid/ivsrcid_vislands30.h"
47b843c749SSergey Zigachev 
48b843c749SSergey Zigachev #include <linux/module.h>
49b843c749SSergey Zigachev #include <linux/moduleparam.h>
50*78973132SSergey Zigachev #if 0
51b843c749SSergey Zigachev #include <linux/version.h>
52*78973132SSergey Zigachev #endif
53b843c749SSergey Zigachev #include <linux/types.h>
54b843c749SSergey Zigachev #include <linux/pm_runtime.h>
55b843c749SSergey Zigachev 
56b843c749SSergey Zigachev #include <drm/drmP.h>
57b843c749SSergey Zigachev #include <drm/drm_atomic.h>
58b843c749SSergey Zigachev #include <drm/drm_atomic_helper.h>
59b843c749SSergey Zigachev #include <drm/drm_dp_mst_helper.h>
60b843c749SSergey Zigachev #include <drm/drm_fb_helper.h>
61b843c749SSergey Zigachev #include <drm/drm_edid.h>
62b843c749SSergey Zigachev 
63b843c749SSergey Zigachev #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
64b843c749SSergey Zigachev #include "ivsrcid/irqsrcs_dcn_1_0.h"
65b843c749SSergey Zigachev 
66b843c749SSergey Zigachev #include "dcn/dcn_1_0_offset.h"
67b843c749SSergey Zigachev #include "dcn/dcn_1_0_sh_mask.h"
68b843c749SSergey Zigachev #include "soc15_hw_ip.h"
69b843c749SSergey Zigachev #include "vega10_ip_offset.h"
70b843c749SSergey Zigachev 
71b843c749SSergey Zigachev #include "soc15_common.h"
72b843c749SSergey Zigachev #endif
73b843c749SSergey Zigachev 
74b843c749SSergey Zigachev #include "modules/inc/mod_freesync.h"
75b843c749SSergey Zigachev 
76b843c749SSergey Zigachev #include "i2caux_interface.h"
77b843c749SSergey Zigachev 
78b843c749SSergey Zigachev /* basic init/fini API */
79b843c749SSergey Zigachev static int amdgpu_dm_init(struct amdgpu_device *adev);
80b843c749SSergey Zigachev static void amdgpu_dm_fini(struct amdgpu_device *adev);
81b843c749SSergey Zigachev 
82b843c749SSergey Zigachev /* initializes drm_device display related structures, based on the information
83b843c749SSergey Zigachev  * provided by DAL. The drm strcutures are: drm_crtc, drm_connector,
84b843c749SSergey Zigachev  * drm_encoder, drm_mode_config
85b843c749SSergey Zigachev  *
86b843c749SSergey Zigachev  * Returns 0 on success
87b843c749SSergey Zigachev  */
88b843c749SSergey Zigachev static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev);
89b843c749SSergey Zigachev /* removes and deallocates the drm structures, created by the above function */
90b843c749SSergey Zigachev static void amdgpu_dm_destroy_drm_device(struct amdgpu_display_manager *dm);
91b843c749SSergey Zigachev 
92b843c749SSergey Zigachev static void
93b843c749SSergey Zigachev amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector);
94b843c749SSergey Zigachev 
95b843c749SSergey Zigachev static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
96b843c749SSergey Zigachev 				struct amdgpu_plane *aplane,
97b843c749SSergey Zigachev 				unsigned long possible_crtcs);
98b843c749SSergey Zigachev static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
99b843c749SSergey Zigachev 			       struct drm_plane *plane,
100b843c749SSergey Zigachev 			       uint32_t link_index);
101b843c749SSergey Zigachev static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
102b843c749SSergey Zigachev 				    struct amdgpu_dm_connector *amdgpu_dm_connector,
103b843c749SSergey Zigachev 				    uint32_t link_index,
104b843c749SSergey Zigachev 				    struct amdgpu_encoder *amdgpu_encoder);
105b843c749SSergey Zigachev static int amdgpu_dm_encoder_init(struct drm_device *dev,
106b843c749SSergey Zigachev 				  struct amdgpu_encoder *aencoder,
107b843c749SSergey Zigachev 				  uint32_t link_index);
108b843c749SSergey Zigachev 
109b843c749SSergey Zigachev static int amdgpu_dm_connector_get_modes(struct drm_connector *connector);
110b843c749SSergey Zigachev 
111b843c749SSergey Zigachev static int amdgpu_dm_atomic_commit(struct drm_device *dev,
112b843c749SSergey Zigachev 				   struct drm_atomic_state *state,
113b843c749SSergey Zigachev 				   bool nonblock);
114b843c749SSergey Zigachev 
115b843c749SSergey Zigachev static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state);
116b843c749SSergey Zigachev 
117b843c749SSergey Zigachev static int amdgpu_dm_atomic_check(struct drm_device *dev,
118b843c749SSergey Zigachev 				  struct drm_atomic_state *state);
119b843c749SSergey Zigachev 
120b843c749SSergey Zigachev 
121b843c749SSergey Zigachev 
122b843c749SSergey Zigachev 
123b843c749SSergey Zigachev static const enum drm_plane_type dm_plane_type_default[AMDGPU_MAX_PLANES] = {
124b843c749SSergey Zigachev 	DRM_PLANE_TYPE_PRIMARY,
125b843c749SSergey Zigachev 	DRM_PLANE_TYPE_PRIMARY,
126b843c749SSergey Zigachev 	DRM_PLANE_TYPE_PRIMARY,
127b843c749SSergey Zigachev 	DRM_PLANE_TYPE_PRIMARY,
128b843c749SSergey Zigachev 	DRM_PLANE_TYPE_PRIMARY,
129b843c749SSergey Zigachev 	DRM_PLANE_TYPE_PRIMARY,
130b843c749SSergey Zigachev };
131b843c749SSergey Zigachev 
132b843c749SSergey Zigachev static const enum drm_plane_type dm_plane_type_carizzo[AMDGPU_MAX_PLANES] = {
133b843c749SSergey Zigachev 	DRM_PLANE_TYPE_PRIMARY,
134b843c749SSergey Zigachev 	DRM_PLANE_TYPE_PRIMARY,
135b843c749SSergey Zigachev 	DRM_PLANE_TYPE_PRIMARY,
136b843c749SSergey Zigachev 	DRM_PLANE_TYPE_OVERLAY,/* YUV Capable Underlay */
137b843c749SSergey Zigachev };
138b843c749SSergey Zigachev 
139b843c749SSergey Zigachev static const enum drm_plane_type dm_plane_type_stoney[AMDGPU_MAX_PLANES] = {
140b843c749SSergey Zigachev 	DRM_PLANE_TYPE_PRIMARY,
141b843c749SSergey Zigachev 	DRM_PLANE_TYPE_PRIMARY,
142b843c749SSergey Zigachev 	DRM_PLANE_TYPE_OVERLAY, /* YUV Capable Underlay */
143b843c749SSergey Zigachev };
144b843c749SSergey Zigachev 
145b843c749SSergey Zigachev /*
146b843c749SSergey Zigachev  * dm_vblank_get_counter
147b843c749SSergey Zigachev  *
148b843c749SSergey Zigachev  * @brief
149b843c749SSergey Zigachev  * Get counter for number of vertical blanks
150b843c749SSergey Zigachev  *
151b843c749SSergey Zigachev  * @param
152b843c749SSergey Zigachev  * struct amdgpu_device *adev - [in] desired amdgpu device
153b843c749SSergey Zigachev  * int disp_idx - [in] which CRTC to get the counter from
154b843c749SSergey Zigachev  *
155b843c749SSergey Zigachev  * @return
156b843c749SSergey Zigachev  * Counter for vertical blanks
157b843c749SSergey Zigachev  */
dm_vblank_get_counter(struct amdgpu_device * adev,int crtc)158b843c749SSergey Zigachev static u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc)
159b843c749SSergey Zigachev {
160b843c749SSergey Zigachev 	if (crtc >= adev->mode_info.num_crtc)
161b843c749SSergey Zigachev 		return 0;
162b843c749SSergey Zigachev 	else {
163b843c749SSergey Zigachev 		struct amdgpu_crtc *acrtc = adev->mode_info.crtcs[crtc];
164b843c749SSergey Zigachev 		struct dm_crtc_state *acrtc_state = to_dm_crtc_state(
165b843c749SSergey Zigachev 				acrtc->base.state);
166b843c749SSergey Zigachev 
167b843c749SSergey Zigachev 
168b843c749SSergey Zigachev 		if (acrtc_state->stream == NULL) {
169b843c749SSergey Zigachev 			DRM_ERROR("dc_stream_state is NULL for crtc '%d'!\n",
170b843c749SSergey Zigachev 				  crtc);
171b843c749SSergey Zigachev 			return 0;
172b843c749SSergey Zigachev 		}
173b843c749SSergey Zigachev 
174b843c749SSergey Zigachev 		return dc_stream_get_vblank_counter(acrtc_state->stream);
175b843c749SSergey Zigachev 	}
176b843c749SSergey Zigachev }
177b843c749SSergey Zigachev 
dm_crtc_get_scanoutpos(struct amdgpu_device * adev,int crtc,u32 * vbl,u32 * position)178b843c749SSergey Zigachev static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
179b843c749SSergey Zigachev 				  u32 *vbl, u32 *position)
180b843c749SSergey Zigachev {
181b843c749SSergey Zigachev 	uint32_t v_blank_start, v_blank_end, h_position, v_position;
182b843c749SSergey Zigachev 
183b843c749SSergey Zigachev 	if ((crtc < 0) || (crtc >= adev->mode_info.num_crtc))
184b843c749SSergey Zigachev 		return -EINVAL;
185b843c749SSergey Zigachev 	else {
186b843c749SSergey Zigachev 		struct amdgpu_crtc *acrtc = adev->mode_info.crtcs[crtc];
187b843c749SSergey Zigachev 		struct dm_crtc_state *acrtc_state = to_dm_crtc_state(
188b843c749SSergey Zigachev 						acrtc->base.state);
189b843c749SSergey Zigachev 
190b843c749SSergey Zigachev 		if (acrtc_state->stream ==  NULL) {
191b843c749SSergey Zigachev 			DRM_ERROR("dc_stream_state is NULL for crtc '%d'!\n",
192b843c749SSergey Zigachev 				  crtc);
193b843c749SSergey Zigachev 			return 0;
194b843c749SSergey Zigachev 		}
195b843c749SSergey Zigachev 
196b843c749SSergey Zigachev 		/*
197b843c749SSergey Zigachev 		 * TODO rework base driver to use values directly.
198b843c749SSergey Zigachev 		 * for now parse it back into reg-format
199b843c749SSergey Zigachev 		 */
200b843c749SSergey Zigachev 		dc_stream_get_scanoutpos(acrtc_state->stream,
201b843c749SSergey Zigachev 					 &v_blank_start,
202b843c749SSergey Zigachev 					 &v_blank_end,
203b843c749SSergey Zigachev 					 &h_position,
204b843c749SSergey Zigachev 					 &v_position);
205b843c749SSergey Zigachev 
206b843c749SSergey Zigachev 		*position = v_position | (h_position << 16);
207b843c749SSergey Zigachev 		*vbl = v_blank_start | (v_blank_end << 16);
208b843c749SSergey Zigachev 	}
209b843c749SSergey Zigachev 
210b843c749SSergey Zigachev 	return 0;
211b843c749SSergey Zigachev }
212b843c749SSergey Zigachev 
dm_is_idle(void * handle)213b843c749SSergey Zigachev static bool dm_is_idle(void *handle)
214b843c749SSergey Zigachev {
215b843c749SSergey Zigachev 	/* XXX todo */
216b843c749SSergey Zigachev 	return true;
217b843c749SSergey Zigachev }
218b843c749SSergey Zigachev 
dm_wait_for_idle(void * handle)219b843c749SSergey Zigachev static int dm_wait_for_idle(void *handle)
220b843c749SSergey Zigachev {
221b843c749SSergey Zigachev 	/* XXX todo */
222b843c749SSergey Zigachev 	return 0;
223b843c749SSergey Zigachev }
224b843c749SSergey Zigachev 
dm_check_soft_reset(void * handle)225b843c749SSergey Zigachev static bool dm_check_soft_reset(void *handle)
226b843c749SSergey Zigachev {
227b843c749SSergey Zigachev 	return false;
228b843c749SSergey Zigachev }
229b843c749SSergey Zigachev 
dm_soft_reset(void * handle)230b843c749SSergey Zigachev static int dm_soft_reset(void *handle)
231b843c749SSergey Zigachev {
232b843c749SSergey Zigachev 	/* XXX todo */
233b843c749SSergey Zigachev 	return 0;
234b843c749SSergey Zigachev }
235b843c749SSergey Zigachev 
236b843c749SSergey Zigachev static struct amdgpu_crtc *
get_crtc_by_otg_inst(struct amdgpu_device * adev,int otg_inst)237b843c749SSergey Zigachev get_crtc_by_otg_inst(struct amdgpu_device *adev,
238b843c749SSergey Zigachev 		     int otg_inst)
239b843c749SSergey Zigachev {
240b843c749SSergey Zigachev 	struct drm_device *dev = adev->ddev;
241b843c749SSergey Zigachev 	struct drm_crtc *crtc;
242b843c749SSergey Zigachev 	struct amdgpu_crtc *amdgpu_crtc;
243b843c749SSergey Zigachev 
244b843c749SSergey Zigachev 	/*
245b843c749SSergey Zigachev 	 * following if is check inherited from both functions where this one is
246b843c749SSergey Zigachev 	 * used now. Need to be checked why it could happen.
247b843c749SSergey Zigachev 	 */
248b843c749SSergey Zigachev 	if (otg_inst == -1) {
249b843c749SSergey Zigachev 		WARN_ON(1);
250b843c749SSergey Zigachev 		return adev->mode_info.crtcs[0];
251b843c749SSergey Zigachev 	}
252b843c749SSergey Zigachev 
253b843c749SSergey Zigachev 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
254b843c749SSergey Zigachev 		amdgpu_crtc = to_amdgpu_crtc(crtc);
255b843c749SSergey Zigachev 
256b843c749SSergey Zigachev 		if (amdgpu_crtc->otg_inst == otg_inst)
257b843c749SSergey Zigachev 			return amdgpu_crtc;
258b843c749SSergey Zigachev 	}
259b843c749SSergey Zigachev 
260b843c749SSergey Zigachev 	return NULL;
261b843c749SSergey Zigachev }
262b843c749SSergey Zigachev 
dm_pflip_high_irq(void * interrupt_params)263b843c749SSergey Zigachev static void dm_pflip_high_irq(void *interrupt_params)
264b843c749SSergey Zigachev {
265b843c749SSergey Zigachev 	struct amdgpu_crtc *amdgpu_crtc;
266b843c749SSergey Zigachev 	struct common_irq_params *irq_params = interrupt_params;
267b843c749SSergey Zigachev 	struct amdgpu_device *adev = irq_params->adev;
268b843c749SSergey Zigachev 	unsigned long flags;
269b843c749SSergey Zigachev 
270b843c749SSergey Zigachev 	amdgpu_crtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_PFLIP);
271b843c749SSergey Zigachev 
272b843c749SSergey Zigachev 	/* IRQ could occur when in initial stage */
273b843c749SSergey Zigachev 	/*TODO work and BO cleanup */
274b843c749SSergey Zigachev 	if (amdgpu_crtc == NULL) {
275b843c749SSergey Zigachev 		DRM_DEBUG_DRIVER("CRTC is null, returning.\n");
276b843c749SSergey Zigachev 		return;
277b843c749SSergey Zigachev 	}
278b843c749SSergey Zigachev 
279b843c749SSergey Zigachev 	spin_lock_irqsave(&adev->ddev->event_lock, flags);
280b843c749SSergey Zigachev 
281b843c749SSergey Zigachev 	if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED){
282b843c749SSergey Zigachev 		DRM_DEBUG_DRIVER("amdgpu_crtc->pflip_status = %d !=AMDGPU_FLIP_SUBMITTED(%d) on crtc:%d[%p] \n",
283b843c749SSergey Zigachev 						 amdgpu_crtc->pflip_status,
284b843c749SSergey Zigachev 						 AMDGPU_FLIP_SUBMITTED,
285b843c749SSergey Zigachev 						 amdgpu_crtc->crtc_id,
286b843c749SSergey Zigachev 						 amdgpu_crtc);
287b843c749SSergey Zigachev 		spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
288b843c749SSergey Zigachev 		return;
289b843c749SSergey Zigachev 	}
290b843c749SSergey Zigachev 
291b843c749SSergey Zigachev 
292b843c749SSergey Zigachev 	/* wakeup usersapce */
293b843c749SSergey Zigachev 	if (amdgpu_crtc->event) {
294b843c749SSergey Zigachev 		/* Update to correct count/ts if racing with vblank irq */
295b843c749SSergey Zigachev 		drm_crtc_accurate_vblank_count(&amdgpu_crtc->base);
296b843c749SSergey Zigachev 
297b843c749SSergey Zigachev 		drm_crtc_send_vblank_event(&amdgpu_crtc->base, amdgpu_crtc->event);
298b843c749SSergey Zigachev 
299b843c749SSergey Zigachev 		/* page flip completed. clean up */
300b843c749SSergey Zigachev 		amdgpu_crtc->event = NULL;
301b843c749SSergey Zigachev 
302b843c749SSergey Zigachev 	} else
303b843c749SSergey Zigachev 		WARN_ON(1);
304b843c749SSergey Zigachev 
305b843c749SSergey Zigachev 	amdgpu_crtc->pflip_status = AMDGPU_FLIP_NONE;
306b843c749SSergey Zigachev 	spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
307b843c749SSergey Zigachev 
308b843c749SSergey Zigachev 	DRM_DEBUG_DRIVER("%s - crtc :%d[%p], pflip_stat:AMDGPU_FLIP_NONE\n",
309b843c749SSergey Zigachev 					__func__, amdgpu_crtc->crtc_id, amdgpu_crtc);
310b843c749SSergey Zigachev 
311b843c749SSergey Zigachev 	drm_crtc_vblank_put(&amdgpu_crtc->base);
312b843c749SSergey Zigachev }
313b843c749SSergey Zigachev 
dm_crtc_high_irq(void * interrupt_params)314b843c749SSergey Zigachev static void dm_crtc_high_irq(void *interrupt_params)
315b843c749SSergey Zigachev {
316b843c749SSergey Zigachev 	struct common_irq_params *irq_params = interrupt_params;
317b843c749SSergey Zigachev 	struct amdgpu_device *adev = irq_params->adev;
318b843c749SSergey Zigachev 	uint8_t crtc_index = 0;
319b843c749SSergey Zigachev 	struct amdgpu_crtc *acrtc;
320b843c749SSergey Zigachev 
321b843c749SSergey Zigachev 	acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK);
322b843c749SSergey Zigachev 
323b843c749SSergey Zigachev 	if (acrtc)
324b843c749SSergey Zigachev 		crtc_index = acrtc->crtc_id;
325b843c749SSergey Zigachev 
326b843c749SSergey Zigachev 	drm_handle_vblank(adev->ddev, crtc_index);
327b843c749SSergey Zigachev 	amdgpu_dm_crtc_handle_crc_irq(&acrtc->base);
328b843c749SSergey Zigachev }
329b843c749SSergey Zigachev 
dm_set_clockgating_state(void * handle,enum amd_clockgating_state state)330b843c749SSergey Zigachev static int dm_set_clockgating_state(void *handle,
331b843c749SSergey Zigachev 		  enum amd_clockgating_state state)
332b843c749SSergey Zigachev {
333b843c749SSergey Zigachev 	return 0;
334b843c749SSergey Zigachev }
335b843c749SSergey Zigachev 
dm_set_powergating_state(void * handle,enum amd_powergating_state state)336b843c749SSergey Zigachev static int dm_set_powergating_state(void *handle,
337b843c749SSergey Zigachev 		  enum amd_powergating_state state)
338b843c749SSergey Zigachev {
339b843c749SSergey Zigachev 	return 0;
340b843c749SSergey Zigachev }
341b843c749SSergey Zigachev 
342b843c749SSergey Zigachev /* Prototypes of private functions */
343b843c749SSergey Zigachev static int dm_early_init(void* handle);
344b843c749SSergey Zigachev 
hotplug_notify_work_func(struct work_struct * work)345b843c749SSergey Zigachev static void hotplug_notify_work_func(struct work_struct *work)
346b843c749SSergey Zigachev {
347b843c749SSergey Zigachev 	struct amdgpu_display_manager *dm = container_of(work, struct amdgpu_display_manager, mst_hotplug_work);
348b843c749SSergey Zigachev 	struct drm_device *dev = dm->ddev;
349b843c749SSergey Zigachev 
350b843c749SSergey Zigachev 	drm_kms_helper_hotplug_event(dev);
351b843c749SSergey Zigachev }
352b843c749SSergey Zigachev 
353b843c749SSergey Zigachev /* Allocate memory for FBC compressed data  */
amdgpu_dm_fbc_init(struct drm_connector * connector)354b843c749SSergey Zigachev static void amdgpu_dm_fbc_init(struct drm_connector *connector)
355b843c749SSergey Zigachev {
356b843c749SSergey Zigachev 	struct drm_device *dev = connector->dev;
357b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev->dev_private;
358b843c749SSergey Zigachev 	struct dm_comressor_info *compressor = &adev->dm.compressor;
359b843c749SSergey Zigachev 	struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(connector);
360b843c749SSergey Zigachev 	struct drm_display_mode *mode;
361b843c749SSergey Zigachev 	unsigned long max_size = 0;
362b843c749SSergey Zigachev 
363b843c749SSergey Zigachev 	if (adev->dm.dc->fbc_compressor == NULL)
364b843c749SSergey Zigachev 		return;
365b843c749SSergey Zigachev 
366b843c749SSergey Zigachev 	if (aconn->dc_link->connector_signal != SIGNAL_TYPE_EDP)
367b843c749SSergey Zigachev 		return;
368b843c749SSergey Zigachev 
369b843c749SSergey Zigachev 	if (compressor->bo_ptr)
370b843c749SSergey Zigachev 		return;
371b843c749SSergey Zigachev 
372b843c749SSergey Zigachev 
373b843c749SSergey Zigachev 	list_for_each_entry(mode, &connector->modes, head) {
374b843c749SSergey Zigachev 		if (max_size < mode->htotal * mode->vtotal)
375b843c749SSergey Zigachev 			max_size = mode->htotal * mode->vtotal;
376b843c749SSergey Zigachev 	}
377b843c749SSergey Zigachev 
378b843c749SSergey Zigachev 	if (max_size) {
379b843c749SSergey Zigachev 		int r = amdgpu_bo_create_kernel(adev, max_size * 4, PAGE_SIZE,
380b843c749SSergey Zigachev 			    AMDGPU_GEM_DOMAIN_GTT, &compressor->bo_ptr,
381*78973132SSergey Zigachev 			    (u64 *)&compressor->gpu_addr, &compressor->cpu_addr);
382b843c749SSergey Zigachev 
383b843c749SSergey Zigachev 		if (r)
384b843c749SSergey Zigachev 			DRM_ERROR("DM: Failed to initialize FBC\n");
385b843c749SSergey Zigachev 		else {
386b843c749SSergey Zigachev 			adev->dm.dc->ctx->fbc_gpu_addr = compressor->gpu_addr;
387b843c749SSergey Zigachev 			DRM_INFO("DM: FBC alloc %lu\n", max_size*4);
388b843c749SSergey Zigachev 		}
389b843c749SSergey Zigachev 
390b843c749SSergey Zigachev 	}
391b843c749SSergey Zigachev 
392b843c749SSergey Zigachev }
393b843c749SSergey Zigachev 
394b843c749SSergey Zigachev 
395b843c749SSergey Zigachev /* Init display KMS
396b843c749SSergey Zigachev  *
397b843c749SSergey Zigachev  * Returns 0 on success
398b843c749SSergey Zigachev  */
amdgpu_dm_init(struct amdgpu_device * adev)399b843c749SSergey Zigachev static int amdgpu_dm_init(struct amdgpu_device *adev)
400b843c749SSergey Zigachev {
401b843c749SSergey Zigachev 	struct dc_init_data init_data;
402b843c749SSergey Zigachev 	adev->dm.ddev = adev->ddev;
403b843c749SSergey Zigachev 	adev->dm.adev = adev;
404b843c749SSergey Zigachev 
405b843c749SSergey Zigachev 	/* Zero all the fields */
406b843c749SSergey Zigachev 	memset(&init_data, 0, sizeof(init_data));
407b843c749SSergey Zigachev 
408b843c749SSergey Zigachev 	if(amdgpu_dm_irq_init(adev)) {
409b843c749SSergey Zigachev 		DRM_ERROR("amdgpu: failed to initialize DM IRQ support.\n");
410b843c749SSergey Zigachev 		goto error;
411b843c749SSergey Zigachev 	}
412b843c749SSergey Zigachev 
413b843c749SSergey Zigachev 	init_data.asic_id.chip_family = adev->family;
414b843c749SSergey Zigachev 
415b843c749SSergey Zigachev 	init_data.asic_id.pci_revision_id = adev->rev_id;
416b843c749SSergey Zigachev 	init_data.asic_id.hw_internal_rev = adev->external_rev_id;
417b843c749SSergey Zigachev 	init_data.asic_id.chip_id = adev->pdev->device;
418b843c749SSergey Zigachev 
419b843c749SSergey Zigachev 	init_data.asic_id.vram_width = adev->gmc.vram_width;
420b843c749SSergey Zigachev 	/* TODO: initialize init_data.asic_id.vram_type here!!!! */
421b843c749SSergey Zigachev 	init_data.asic_id.atombios_base_address =
422b843c749SSergey Zigachev 		adev->mode_info.atom_context->bios;
423b843c749SSergey Zigachev 
424b843c749SSergey Zigachev 	init_data.driver = adev;
425b843c749SSergey Zigachev 
426b843c749SSergey Zigachev 	adev->dm.cgs_device = amdgpu_cgs_create_device(adev);
427b843c749SSergey Zigachev 
428b843c749SSergey Zigachev 	if (!adev->dm.cgs_device) {
429b843c749SSergey Zigachev 		DRM_ERROR("amdgpu: failed to create cgs device.\n");
430b843c749SSergey Zigachev 		goto error;
431b843c749SSergey Zigachev 	}
432b843c749SSergey Zigachev 
433b843c749SSergey Zigachev 	init_data.cgs_device = adev->dm.cgs_device;
434b843c749SSergey Zigachev 
435b843c749SSergey Zigachev 	adev->dm.dal = NULL;
436b843c749SSergey Zigachev 
437b843c749SSergey Zigachev 	init_data.dce_environment = DCE_ENV_PRODUCTION_DRV;
438b843c749SSergey Zigachev 
439b843c749SSergey Zigachev 	/*
440b843c749SSergey Zigachev 	 * TODO debug why this doesn't work on Raven
441b843c749SSergey Zigachev 	 */
442b843c749SSergey Zigachev 	if (adev->flags & AMD_IS_APU &&
443b843c749SSergey Zigachev 	    adev->asic_type >= CHIP_CARRIZO &&
444b843c749SSergey Zigachev 	    adev->asic_type < CHIP_RAVEN)
445b843c749SSergey Zigachev 		init_data.flags.gpu_vm_support = true;
446b843c749SSergey Zigachev 
447b843c749SSergey Zigachev 	/* Display Core create. */
448b843c749SSergey Zigachev 	adev->dm.dc = dc_create(&init_data);
449b843c749SSergey Zigachev 
450b843c749SSergey Zigachev 	if (adev->dm.dc) {
451b843c749SSergey Zigachev 		DRM_INFO("Display Core initialized with v%s!\n", DC_VER);
452b843c749SSergey Zigachev 	} else {
453b843c749SSergey Zigachev 		DRM_INFO("Display Core failed to initialize with v%s!\n", DC_VER);
454b843c749SSergey Zigachev 		goto error;
455b843c749SSergey Zigachev 	}
456b843c749SSergey Zigachev 
457b843c749SSergey Zigachev 	INIT_WORK(&adev->dm.mst_hotplug_work, hotplug_notify_work_func);
458b843c749SSergey Zigachev 
459b843c749SSergey Zigachev 	adev->dm.freesync_module = mod_freesync_create(adev->dm.dc);
460b843c749SSergey Zigachev 	if (!adev->dm.freesync_module) {
461b843c749SSergey Zigachev 		DRM_ERROR(
462b843c749SSergey Zigachev 		"amdgpu: failed to initialize freesync_module.\n");
463b843c749SSergey Zigachev 	} else
464b843c749SSergey Zigachev 		DRM_DEBUG_DRIVER("amdgpu: freesync_module init done %p.\n",
465b843c749SSergey Zigachev 				adev->dm.freesync_module);
466b843c749SSergey Zigachev 
467b843c749SSergey Zigachev 	amdgpu_dm_init_color_mod();
468b843c749SSergey Zigachev 
469b843c749SSergey Zigachev 	if (amdgpu_dm_initialize_drm_device(adev)) {
470b843c749SSergey Zigachev 		DRM_ERROR(
471b843c749SSergey Zigachev 		"amdgpu: failed to initialize sw for display support.\n");
472b843c749SSergey Zigachev 		goto error;
473b843c749SSergey Zigachev 	}
474b843c749SSergey Zigachev 
475b843c749SSergey Zigachev 	/* Update the actual used number of crtc */
476b843c749SSergey Zigachev 	adev->mode_info.num_crtc = adev->dm.display_indexes_num;
477b843c749SSergey Zigachev 
478b843c749SSergey Zigachev 	/* TODO: Add_display_info? */
479b843c749SSergey Zigachev 
480b843c749SSergey Zigachev 	/* TODO use dynamic cursor width */
481b843c749SSergey Zigachev 	adev->ddev->mode_config.cursor_width = adev->dm.dc->caps.max_cursor_size;
482b843c749SSergey Zigachev 	adev->ddev->mode_config.cursor_height = adev->dm.dc->caps.max_cursor_size;
483b843c749SSergey Zigachev 
484b843c749SSergey Zigachev 	if (drm_vblank_init(adev->ddev, adev->dm.display_indexes_num)) {
485b843c749SSergey Zigachev 		DRM_ERROR(
486b843c749SSergey Zigachev 		"amdgpu: failed to initialize sw for display support.\n");
487b843c749SSergey Zigachev 		goto error;
488b843c749SSergey Zigachev 	}
489b843c749SSergey Zigachev 
490b843c749SSergey Zigachev 	DRM_DEBUG_DRIVER("KMS initialized.\n");
491b843c749SSergey Zigachev 
492b843c749SSergey Zigachev 	return 0;
493b843c749SSergey Zigachev error:
494b843c749SSergey Zigachev 	amdgpu_dm_fini(adev);
495b843c749SSergey Zigachev 
496b843c749SSergey Zigachev 	return -1;
497b843c749SSergey Zigachev }
498b843c749SSergey Zigachev 
amdgpu_dm_fini(struct amdgpu_device * adev)499b843c749SSergey Zigachev static void amdgpu_dm_fini(struct amdgpu_device *adev)
500b843c749SSergey Zigachev {
501b843c749SSergey Zigachev 	amdgpu_dm_destroy_drm_device(&adev->dm);
502b843c749SSergey Zigachev 	/*
503b843c749SSergey Zigachev 	 * TODO: pageflip, vlank interrupt
504b843c749SSergey Zigachev 	 *
505b843c749SSergey Zigachev 	 * amdgpu_dm_irq_fini(adev);
506b843c749SSergey Zigachev 	 */
507b843c749SSergey Zigachev 
508b843c749SSergey Zigachev 	if (adev->dm.cgs_device) {
509b843c749SSergey Zigachev 		amdgpu_cgs_destroy_device(adev->dm.cgs_device);
510b843c749SSergey Zigachev 		adev->dm.cgs_device = NULL;
511b843c749SSergey Zigachev 	}
512b843c749SSergey Zigachev 	if (adev->dm.freesync_module) {
513b843c749SSergey Zigachev 		mod_freesync_destroy(adev->dm.freesync_module);
514b843c749SSergey Zigachev 		adev->dm.freesync_module = NULL;
515b843c749SSergey Zigachev 	}
516b843c749SSergey Zigachev 	/* DC Destroy TODO: Replace destroy DAL */
517b843c749SSergey Zigachev 	if (adev->dm.dc)
518b843c749SSergey Zigachev 		dc_destroy(&adev->dm.dc);
519b843c749SSergey Zigachev 	return;
520b843c749SSergey Zigachev }
521b843c749SSergey Zigachev 
dm_sw_init(void * handle)522b843c749SSergey Zigachev static int dm_sw_init(void *handle)
523b843c749SSergey Zigachev {
524b843c749SSergey Zigachev 	return 0;
525b843c749SSergey Zigachev }
526b843c749SSergey Zigachev 
dm_sw_fini(void * handle)527b843c749SSergey Zigachev static int dm_sw_fini(void *handle)
528b843c749SSergey Zigachev {
529b843c749SSergey Zigachev 	return 0;
530b843c749SSergey Zigachev }
531b843c749SSergey Zigachev 
detect_mst_link_for_all_connectors(struct drm_device * dev)532b843c749SSergey Zigachev static int detect_mst_link_for_all_connectors(struct drm_device *dev)
533b843c749SSergey Zigachev {
534b843c749SSergey Zigachev 	struct amdgpu_dm_connector *aconnector;
535b843c749SSergey Zigachev 	struct drm_connector *connector;
536b843c749SSergey Zigachev 	int ret = 0;
537b843c749SSergey Zigachev 
538b843c749SSergey Zigachev 	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
539b843c749SSergey Zigachev 
540b843c749SSergey Zigachev 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
541b843c749SSergey Zigachev 		aconnector = to_amdgpu_dm_connector(connector);
542b843c749SSergey Zigachev 		if (aconnector->dc_link->type == dc_connection_mst_branch &&
543b843c749SSergey Zigachev 		    aconnector->mst_mgr.aux) {
544b843c749SSergey Zigachev 			DRM_DEBUG_DRIVER("DM_MST: starting TM on aconnector: %p [id: %d]\n",
545b843c749SSergey Zigachev 					aconnector, aconnector->base.base.id);
546b843c749SSergey Zigachev 
547b843c749SSergey Zigachev 			ret = drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, true);
548b843c749SSergey Zigachev 			if (ret < 0) {
549b843c749SSergey Zigachev 				DRM_ERROR("DM_MST: Failed to start MST\n");
550b843c749SSergey Zigachev 				((struct dc_link *)aconnector->dc_link)->type = dc_connection_single;
551b843c749SSergey Zigachev 				return ret;
552b843c749SSergey Zigachev 				}
553b843c749SSergey Zigachev 			}
554b843c749SSergey Zigachev 	}
555b843c749SSergey Zigachev 
556b843c749SSergey Zigachev 	drm_modeset_unlock(&dev->mode_config.connection_mutex);
557b843c749SSergey Zigachev 	return ret;
558b843c749SSergey Zigachev }
559b843c749SSergey Zigachev 
dm_late_init(void * handle)560b843c749SSergey Zigachev static int dm_late_init(void *handle)
561b843c749SSergey Zigachev {
562b843c749SSergey Zigachev 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
563b843c749SSergey Zigachev 
564b843c749SSergey Zigachev 	return detect_mst_link_for_all_connectors(adev->ddev);
565b843c749SSergey Zigachev }
566b843c749SSergey Zigachev 
s3_handle_mst(struct drm_device * dev,bool suspend)567b843c749SSergey Zigachev static void s3_handle_mst(struct drm_device *dev, bool suspend)
568b843c749SSergey Zigachev {
569b843c749SSergey Zigachev 	struct amdgpu_dm_connector *aconnector;
570b843c749SSergey Zigachev 	struct drm_connector *connector;
571b843c749SSergey Zigachev 	struct drm_dp_mst_topology_mgr *mgr;
572b843c749SSergey Zigachev 	int ret;
573b843c749SSergey Zigachev 	bool need_hotplug = false;
574b843c749SSergey Zigachev 
575b843c749SSergey Zigachev 	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
576b843c749SSergey Zigachev 
577b843c749SSergey Zigachev 	list_for_each_entry(connector, &dev->mode_config.connector_list,
578b843c749SSergey Zigachev 			    head) {
579b843c749SSergey Zigachev 		aconnector = to_amdgpu_dm_connector(connector);
580b843c749SSergey Zigachev 		if (aconnector->dc_link->type != dc_connection_mst_branch ||
581b843c749SSergey Zigachev 		    aconnector->mst_port)
582b843c749SSergey Zigachev 			continue;
583b843c749SSergey Zigachev 
584b843c749SSergey Zigachev 		mgr = &aconnector->mst_mgr;
585b843c749SSergey Zigachev 
586b843c749SSergey Zigachev 		if (suspend) {
587b843c749SSergey Zigachev 			drm_dp_mst_topology_mgr_suspend(mgr);
588b843c749SSergey Zigachev 		} else {
589b843c749SSergey Zigachev 			ret = drm_dp_mst_topology_mgr_resume(mgr);
590b843c749SSergey Zigachev 			if (ret < 0) {
591b843c749SSergey Zigachev 				drm_dp_mst_topology_mgr_set_mst(mgr, false);
592b843c749SSergey Zigachev 				need_hotplug = true;
593b843c749SSergey Zigachev 			}
594b843c749SSergey Zigachev 		}
595b843c749SSergey Zigachev 	}
596b843c749SSergey Zigachev 
597b843c749SSergey Zigachev 	drm_modeset_unlock(&dev->mode_config.connection_mutex);
598b843c749SSergey Zigachev 
599b843c749SSergey Zigachev 	if (need_hotplug)
600b843c749SSergey Zigachev 		drm_kms_helper_hotplug_event(dev);
601b843c749SSergey Zigachev }
602b843c749SSergey Zigachev 
dm_hw_init(void * handle)603b843c749SSergey Zigachev static int dm_hw_init(void *handle)
604b843c749SSergey Zigachev {
605b843c749SSergey Zigachev 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
606b843c749SSergey Zigachev 	/* Create DAL display manager */
607b843c749SSergey Zigachev 	amdgpu_dm_init(adev);
608b843c749SSergey Zigachev 	amdgpu_dm_hpd_init(adev);
609b843c749SSergey Zigachev 
610b843c749SSergey Zigachev 	return 0;
611b843c749SSergey Zigachev }
612b843c749SSergey Zigachev 
dm_hw_fini(void * handle)613b843c749SSergey Zigachev static int dm_hw_fini(void *handle)
614b843c749SSergey Zigachev {
615b843c749SSergey Zigachev 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
616b843c749SSergey Zigachev 
617b843c749SSergey Zigachev 	amdgpu_dm_hpd_fini(adev);
618b843c749SSergey Zigachev 
619b843c749SSergey Zigachev 	amdgpu_dm_irq_fini(adev);
620b843c749SSergey Zigachev 	amdgpu_dm_fini(adev);
621b843c749SSergey Zigachev 	return 0;
622b843c749SSergey Zigachev }
623b843c749SSergey Zigachev 
dm_suspend(void * handle)624b843c749SSergey Zigachev static int dm_suspend(void *handle)
625b843c749SSergey Zigachev {
626b843c749SSergey Zigachev 	struct amdgpu_device *adev = handle;
627b843c749SSergey Zigachev 	struct amdgpu_display_manager *dm = &adev->dm;
628b843c749SSergey Zigachev 	int ret = 0;
629b843c749SSergey Zigachev 
630b843c749SSergey Zigachev 	WARN_ON(adev->dm.cached_state);
631b843c749SSergey Zigachev 	adev->dm.cached_state = drm_atomic_helper_suspend(adev->ddev);
632b843c749SSergey Zigachev 
633b843c749SSergey Zigachev 	s3_handle_mst(adev->ddev, true);
634b843c749SSergey Zigachev 
635b843c749SSergey Zigachev 	amdgpu_dm_irq_suspend(adev);
636b843c749SSergey Zigachev 
637b843c749SSergey Zigachev 
638b843c749SSergey Zigachev 	dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D3);
639b843c749SSergey Zigachev 
640b843c749SSergey Zigachev 	return ret;
641b843c749SSergey Zigachev }
642b843c749SSergey Zigachev 
643b843c749SSergey Zigachev static struct amdgpu_dm_connector *
amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_state * state,struct drm_crtc * crtc)644b843c749SSergey Zigachev amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_state *state,
645b843c749SSergey Zigachev 					     struct drm_crtc *crtc)
646b843c749SSergey Zigachev {
647b843c749SSergey Zigachev 	uint32_t i;
648b843c749SSergey Zigachev 	struct drm_connector_state *new_con_state;
649b843c749SSergey Zigachev 	struct drm_connector *connector;
650b843c749SSergey Zigachev 	struct drm_crtc *crtc_from_state;
651b843c749SSergey Zigachev 
652b843c749SSergey Zigachev 	for_each_new_connector_in_state(state, connector, new_con_state, i) {
653b843c749SSergey Zigachev 		crtc_from_state = new_con_state->crtc;
654b843c749SSergey Zigachev 
655b843c749SSergey Zigachev 		if (crtc_from_state == crtc)
656b843c749SSergey Zigachev 			return to_amdgpu_dm_connector(connector);
657b843c749SSergey Zigachev 	}
658b843c749SSergey Zigachev 
659b843c749SSergey Zigachev 	return NULL;
660b843c749SSergey Zigachev }
661b843c749SSergey Zigachev 
emulated_link_detect(struct dc_link * link)662b843c749SSergey Zigachev static void emulated_link_detect(struct dc_link *link)
663b843c749SSergey Zigachev {
664b843c749SSergey Zigachev 	struct dc_sink_init_data sink_init_data = { 0 };
665b843c749SSergey Zigachev 	struct display_sink_capability sink_caps = { 0 };
666b843c749SSergey Zigachev 	enum dc_edid_status edid_status;
667b843c749SSergey Zigachev 	struct dc_context *dc_ctx = link->ctx;
668b843c749SSergey Zigachev 	struct dc_sink *sink = NULL;
669b843c749SSergey Zigachev 	struct dc_sink *prev_sink = NULL;
670b843c749SSergey Zigachev 
671b843c749SSergey Zigachev 	link->type = dc_connection_none;
672b843c749SSergey Zigachev 	prev_sink = link->local_sink;
673b843c749SSergey Zigachev 
674b843c749SSergey Zigachev 	if (prev_sink)
675b843c749SSergey Zigachev 		dc_sink_release(prev_sink);
676b843c749SSergey Zigachev 
677b843c749SSergey Zigachev 	switch (link->connector_signal) {
678b843c749SSergey Zigachev 	case SIGNAL_TYPE_HDMI_TYPE_A: {
679b843c749SSergey Zigachev 		sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C;
680b843c749SSergey Zigachev 		sink_caps.signal = SIGNAL_TYPE_HDMI_TYPE_A;
681b843c749SSergey Zigachev 		break;
682b843c749SSergey Zigachev 	}
683b843c749SSergey Zigachev 
684b843c749SSergey Zigachev 	case SIGNAL_TYPE_DVI_SINGLE_LINK: {
685b843c749SSergey Zigachev 		sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C;
686b843c749SSergey Zigachev 		sink_caps.signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
687b843c749SSergey Zigachev 		break;
688b843c749SSergey Zigachev 	}
689b843c749SSergey Zigachev 
690b843c749SSergey Zigachev 	case SIGNAL_TYPE_DVI_DUAL_LINK: {
691b843c749SSergey Zigachev 		sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C;
692b843c749SSergey Zigachev 		sink_caps.signal = SIGNAL_TYPE_DVI_DUAL_LINK;
693b843c749SSergey Zigachev 		break;
694b843c749SSergey Zigachev 	}
695b843c749SSergey Zigachev 
696b843c749SSergey Zigachev 	case SIGNAL_TYPE_LVDS: {
697b843c749SSergey Zigachev 		sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C;
698b843c749SSergey Zigachev 		sink_caps.signal = SIGNAL_TYPE_LVDS;
699b843c749SSergey Zigachev 		break;
700b843c749SSergey Zigachev 	}
701b843c749SSergey Zigachev 
702b843c749SSergey Zigachev 	case SIGNAL_TYPE_EDP: {
703b843c749SSergey Zigachev 		sink_caps.transaction_type =
704b843c749SSergey Zigachev 			DDC_TRANSACTION_TYPE_I2C_OVER_AUX;
705b843c749SSergey Zigachev 		sink_caps.signal = SIGNAL_TYPE_EDP;
706b843c749SSergey Zigachev 		break;
707b843c749SSergey Zigachev 	}
708b843c749SSergey Zigachev 
709b843c749SSergey Zigachev 	case SIGNAL_TYPE_DISPLAY_PORT: {
710b843c749SSergey Zigachev 		sink_caps.transaction_type =
711b843c749SSergey Zigachev 			DDC_TRANSACTION_TYPE_I2C_OVER_AUX;
712b843c749SSergey Zigachev 		sink_caps.signal = SIGNAL_TYPE_VIRTUAL;
713b843c749SSergey Zigachev 		break;
714b843c749SSergey Zigachev 	}
715b843c749SSergey Zigachev 
716b843c749SSergey Zigachev 	default:
717b843c749SSergey Zigachev 		DC_ERROR("Invalid connector type! signal:%d\n",
718b843c749SSergey Zigachev 			link->connector_signal);
719b843c749SSergey Zigachev 		return;
720b843c749SSergey Zigachev 	}
721b843c749SSergey Zigachev 
722b843c749SSergey Zigachev 	sink_init_data.link = link;
723b843c749SSergey Zigachev 	sink_init_data.sink_signal = sink_caps.signal;
724b843c749SSergey Zigachev 
725b843c749SSergey Zigachev 	sink = dc_sink_create(&sink_init_data);
726b843c749SSergey Zigachev 	if (!sink) {
727b843c749SSergey Zigachev 		DC_ERROR("Failed to create sink!\n");
728b843c749SSergey Zigachev 		return;
729b843c749SSergey Zigachev 	}
730b843c749SSergey Zigachev 
731b843c749SSergey Zigachev 	link->local_sink = sink;
732b843c749SSergey Zigachev 
733b843c749SSergey Zigachev 	edid_status = dm_helpers_read_local_edid(
734b843c749SSergey Zigachev 			link->ctx,
735b843c749SSergey Zigachev 			link,
736b843c749SSergey Zigachev 			sink);
737b843c749SSergey Zigachev 
738b843c749SSergey Zigachev 	if (edid_status != EDID_OK)
739b843c749SSergey Zigachev 		DC_ERROR("Failed to read EDID");
740b843c749SSergey Zigachev 
741b843c749SSergey Zigachev }
742b843c749SSergey Zigachev 
dm_resume(void * handle)743b843c749SSergey Zigachev static int dm_resume(void *handle)
744b843c749SSergey Zigachev {
745b843c749SSergey Zigachev 	struct amdgpu_device *adev = handle;
746b843c749SSergey Zigachev 	struct drm_device *ddev = adev->ddev;
747b843c749SSergey Zigachev 	struct amdgpu_display_manager *dm = &adev->dm;
748b843c749SSergey Zigachev 	struct amdgpu_dm_connector *aconnector;
749b843c749SSergey Zigachev 	struct drm_connector *connector;
750b843c749SSergey Zigachev 	struct drm_crtc *crtc;
751b843c749SSergey Zigachev 	struct drm_crtc_state *new_crtc_state;
752b843c749SSergey Zigachev 	struct dm_crtc_state *dm_new_crtc_state;
753b843c749SSergey Zigachev 	struct drm_plane *plane;
754b843c749SSergey Zigachev 	struct drm_plane_state *new_plane_state;
755b843c749SSergey Zigachev 	struct dm_plane_state *dm_new_plane_state;
756b843c749SSergey Zigachev 	enum dc_connection_type new_connection_type = dc_connection_none;
757b843c749SSergey Zigachev 	int i;
758b843c749SSergey Zigachev 
759b843c749SSergey Zigachev 	/* power on hardware */
760b843c749SSergey Zigachev 	dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D0);
761b843c749SSergey Zigachev 
762b843c749SSergey Zigachev 	/* program HPD filter */
763b843c749SSergey Zigachev 	dc_resume(dm->dc);
764b843c749SSergey Zigachev 
765b843c749SSergey Zigachev 	/* On resume we need to  rewrite the MSTM control bits to enamble MST*/
766b843c749SSergey Zigachev 	s3_handle_mst(ddev, false);
767b843c749SSergey Zigachev 
768b843c749SSergey Zigachev 	/*
769b843c749SSergey Zigachev 	 * early enable HPD Rx IRQ, should be done before set mode as short
770b843c749SSergey Zigachev 	 * pulse interrupts are used for MST
771b843c749SSergey Zigachev 	 */
772b843c749SSergey Zigachev 	amdgpu_dm_irq_resume_early(adev);
773b843c749SSergey Zigachev 
774b843c749SSergey Zigachev 	/* Do detection*/
775b843c749SSergey Zigachev 	list_for_each_entry(connector, &ddev->mode_config.connector_list, head) {
776b843c749SSergey Zigachev 		aconnector = to_amdgpu_dm_connector(connector);
777b843c749SSergey Zigachev 
778b843c749SSergey Zigachev 		/*
779b843c749SSergey Zigachev 		 * this is the case when traversing through already created
780b843c749SSergey Zigachev 		 * MST connectors, should be skipped
781b843c749SSergey Zigachev 		 */
782b843c749SSergey Zigachev 		if (aconnector->mst_port)
783b843c749SSergey Zigachev 			continue;
784b843c749SSergey Zigachev 
785b843c749SSergey Zigachev 		mutex_lock(&aconnector->hpd_lock);
786b843c749SSergey Zigachev 		if (!dc_link_detect_sink(aconnector->dc_link, &new_connection_type))
787b843c749SSergey Zigachev 			DRM_ERROR("KMS: Failed to detect connector\n");
788b843c749SSergey Zigachev 
789b843c749SSergey Zigachev 		if (aconnector->base.force && new_connection_type == dc_connection_none)
790b843c749SSergey Zigachev 			emulated_link_detect(aconnector->dc_link);
791b843c749SSergey Zigachev 		else
792b843c749SSergey Zigachev 			dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD);
793b843c749SSergey Zigachev 
794b843c749SSergey Zigachev 		if (aconnector->fake_enable && aconnector->dc_link->local_sink)
795b843c749SSergey Zigachev 			aconnector->fake_enable = false;
796b843c749SSergey Zigachev 
797b843c749SSergey Zigachev 		aconnector->dc_sink = NULL;
798b843c749SSergey Zigachev 		amdgpu_dm_update_connector_after_detect(aconnector);
799b843c749SSergey Zigachev 		mutex_unlock(&aconnector->hpd_lock);
800b843c749SSergey Zigachev 	}
801b843c749SSergey Zigachev 
802b843c749SSergey Zigachev 	/* Force mode set in atomic comit */
803b843c749SSergey Zigachev 	for_each_new_crtc_in_state(dm->cached_state, crtc, new_crtc_state, i)
804b843c749SSergey Zigachev 		new_crtc_state->active_changed = true;
805b843c749SSergey Zigachev 
806b843c749SSergey Zigachev 	/*
807b843c749SSergey Zigachev 	 * atomic_check is expected to create the dc states. We need to release
808b843c749SSergey Zigachev 	 * them here, since they were duplicated as part of the suspend
809b843c749SSergey Zigachev 	 * procedure.
810b843c749SSergey Zigachev 	 */
811b843c749SSergey Zigachev 	for_each_new_crtc_in_state(dm->cached_state, crtc, new_crtc_state, i) {
812b843c749SSergey Zigachev 		dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
813b843c749SSergey Zigachev 		if (dm_new_crtc_state->stream) {
814b843c749SSergey Zigachev 			WARN_ON(kref_read(&dm_new_crtc_state->stream->refcount) > 1);
815b843c749SSergey Zigachev 			dc_stream_release(dm_new_crtc_state->stream);
816b843c749SSergey Zigachev 			dm_new_crtc_state->stream = NULL;
817b843c749SSergey Zigachev 		}
818b843c749SSergey Zigachev 	}
819b843c749SSergey Zigachev 
820b843c749SSergey Zigachev 	for_each_new_plane_in_state(dm->cached_state, plane, new_plane_state, i) {
821b843c749SSergey Zigachev 		dm_new_plane_state = to_dm_plane_state(new_plane_state);
822b843c749SSergey Zigachev 		if (dm_new_plane_state->dc_state) {
823b843c749SSergey Zigachev 			WARN_ON(kref_read(&dm_new_plane_state->dc_state->refcount) > 1);
824b843c749SSergey Zigachev 			dc_plane_state_release(dm_new_plane_state->dc_state);
825b843c749SSergey Zigachev 			dm_new_plane_state->dc_state = NULL;
826b843c749SSergey Zigachev 		}
827b843c749SSergey Zigachev 	}
828b843c749SSergey Zigachev 
829b843c749SSergey Zigachev 	drm_atomic_helper_resume(ddev, dm->cached_state);
830b843c749SSergey Zigachev 
831b843c749SSergey Zigachev 	dm->cached_state = NULL;
832b843c749SSergey Zigachev 
833b843c749SSergey Zigachev 	amdgpu_dm_irq_resume_late(adev);
834b843c749SSergey Zigachev 
835b843c749SSergey Zigachev 	return 0;
836b843c749SSergey Zigachev }
837b843c749SSergey Zigachev 
838b843c749SSergey Zigachev static const struct amd_ip_funcs amdgpu_dm_funcs = {
839b843c749SSergey Zigachev 	.name = "dm",
840b843c749SSergey Zigachev 	.early_init = dm_early_init,
841b843c749SSergey Zigachev 	.late_init = dm_late_init,
842b843c749SSergey Zigachev 	.sw_init = dm_sw_init,
843b843c749SSergey Zigachev 	.sw_fini = dm_sw_fini,
844b843c749SSergey Zigachev 	.hw_init = dm_hw_init,
845b843c749SSergey Zigachev 	.hw_fini = dm_hw_fini,
846b843c749SSergey Zigachev 	.suspend = dm_suspend,
847b843c749SSergey Zigachev 	.resume = dm_resume,
848b843c749SSergey Zigachev 	.is_idle = dm_is_idle,
849b843c749SSergey Zigachev 	.wait_for_idle = dm_wait_for_idle,
850b843c749SSergey Zigachev 	.check_soft_reset = dm_check_soft_reset,
851b843c749SSergey Zigachev 	.soft_reset = dm_soft_reset,
852b843c749SSergey Zigachev 	.set_clockgating_state = dm_set_clockgating_state,
853b843c749SSergey Zigachev 	.set_powergating_state = dm_set_powergating_state,
854b843c749SSergey Zigachev };
855b843c749SSergey Zigachev 
856b843c749SSergey Zigachev const struct amdgpu_ip_block_version dm_ip_block =
857b843c749SSergey Zigachev {
858b843c749SSergey Zigachev 	.type = AMD_IP_BLOCK_TYPE_DCE,
859b843c749SSergey Zigachev 	.major = 1,
860b843c749SSergey Zigachev 	.minor = 0,
861b843c749SSergey Zigachev 	.rev = 0,
862b843c749SSergey Zigachev 	.funcs = &amdgpu_dm_funcs,
863b843c749SSergey Zigachev };
864b843c749SSergey Zigachev 
865b843c749SSergey Zigachev 
866b843c749SSergey Zigachev static struct drm_atomic_state *
dm_atomic_state_alloc(struct drm_device * dev)867b843c749SSergey Zigachev dm_atomic_state_alloc(struct drm_device *dev)
868b843c749SSergey Zigachev {
869b843c749SSergey Zigachev 	struct dm_atomic_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
870b843c749SSergey Zigachev 
871b843c749SSergey Zigachev 	if (!state)
872b843c749SSergey Zigachev 		return NULL;
873b843c749SSergey Zigachev 
874b843c749SSergey Zigachev 	if (drm_atomic_state_init(dev, &state->base) < 0)
875b843c749SSergey Zigachev 		goto fail;
876b843c749SSergey Zigachev 
877b843c749SSergey Zigachev 	return &state->base;
878b843c749SSergey Zigachev 
879b843c749SSergey Zigachev fail:
880b843c749SSergey Zigachev 	kfree(state);
881b843c749SSergey Zigachev 	return NULL;
882b843c749SSergey Zigachev }
883b843c749SSergey Zigachev 
884b843c749SSergey Zigachev static void
dm_atomic_state_clear(struct drm_atomic_state * state)885b843c749SSergey Zigachev dm_atomic_state_clear(struct drm_atomic_state *state)
886b843c749SSergey Zigachev {
887b843c749SSergey Zigachev 	struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
888b843c749SSergey Zigachev 
889b843c749SSergey Zigachev 	if (dm_state->context) {
890b843c749SSergey Zigachev 		dc_release_state(dm_state->context);
891b843c749SSergey Zigachev 		dm_state->context = NULL;
892b843c749SSergey Zigachev 	}
893b843c749SSergey Zigachev 
894b843c749SSergey Zigachev 	drm_atomic_state_default_clear(state);
895b843c749SSergey Zigachev }
896b843c749SSergey Zigachev 
897b843c749SSergey Zigachev static void
dm_atomic_state_alloc_free(struct drm_atomic_state * state)898b843c749SSergey Zigachev dm_atomic_state_alloc_free(struct drm_atomic_state *state)
899b843c749SSergey Zigachev {
900b843c749SSergey Zigachev 	struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
901b843c749SSergey Zigachev 	drm_atomic_state_default_release(state);
902b843c749SSergey Zigachev 	kfree(dm_state);
903b843c749SSergey Zigachev }
904b843c749SSergey Zigachev 
905b843c749SSergey Zigachev static const struct drm_mode_config_funcs amdgpu_dm_mode_funcs = {
906b843c749SSergey Zigachev 	.fb_create = amdgpu_display_user_framebuffer_create,
907b843c749SSergey Zigachev 	.output_poll_changed = drm_fb_helper_output_poll_changed,
908b843c749SSergey Zigachev 	.atomic_check = amdgpu_dm_atomic_check,
909b843c749SSergey Zigachev 	.atomic_commit = amdgpu_dm_atomic_commit,
910b843c749SSergey Zigachev 	.atomic_state_alloc = dm_atomic_state_alloc,
911b843c749SSergey Zigachev 	.atomic_state_clear = dm_atomic_state_clear,
912b843c749SSergey Zigachev 	.atomic_state_free = dm_atomic_state_alloc_free
913b843c749SSergey Zigachev };
914b843c749SSergey Zigachev 
915b843c749SSergey Zigachev static struct drm_mode_config_helper_funcs amdgpu_dm_mode_config_helperfuncs = {
916b843c749SSergey Zigachev 	.atomic_commit_tail = amdgpu_dm_atomic_commit_tail
917b843c749SSergey Zigachev };
918b843c749SSergey Zigachev 
919b843c749SSergey Zigachev static void
amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector * aconnector)920b843c749SSergey Zigachev amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector)
921b843c749SSergey Zigachev {
922b843c749SSergey Zigachev 	struct drm_connector *connector = &aconnector->base;
923b843c749SSergey Zigachev 	struct drm_device *dev = connector->dev;
924b843c749SSergey Zigachev 	struct dc_sink *sink;
925b843c749SSergey Zigachev 
926b843c749SSergey Zigachev 	/* MST handled by drm_mst framework */
927b843c749SSergey Zigachev 	if (aconnector->mst_mgr.mst_state == true)
928b843c749SSergey Zigachev 		return;
929b843c749SSergey Zigachev 
930b843c749SSergey Zigachev 
931b843c749SSergey Zigachev 	sink = aconnector->dc_link->local_sink;
932b843c749SSergey Zigachev 
933b843c749SSergey Zigachev 	/* Edid mgmt connector gets first update only in mode_valid hook and then
934b843c749SSergey Zigachev 	 * the connector sink is set to either fake or physical sink depends on link status.
935b843c749SSergey Zigachev 	 * don't do it here if u are during boot
936b843c749SSergey Zigachev 	 */
937b843c749SSergey Zigachev 	if (aconnector->base.force != DRM_FORCE_UNSPECIFIED
938b843c749SSergey Zigachev 			&& aconnector->dc_em_sink) {
939b843c749SSergey Zigachev 
940b843c749SSergey Zigachev 		/* For S3 resume with headless use eml_sink to fake stream
941b843c749SSergey Zigachev 		 * because on resume connecotr->sink is set ti NULL
942b843c749SSergey Zigachev 		 */
943b843c749SSergey Zigachev 		mutex_lock(&dev->mode_config.mutex);
944b843c749SSergey Zigachev 
945b843c749SSergey Zigachev 		if (sink) {
946b843c749SSergey Zigachev 			if (aconnector->dc_sink) {
947b843c749SSergey Zigachev 				amdgpu_dm_remove_sink_from_freesync_module(
948b843c749SSergey Zigachev 								connector);
949b843c749SSergey Zigachev 				/* retain and release bellow are used for
950b843c749SSergey Zigachev 				 * bump up refcount for sink because the link don't point
951b843c749SSergey Zigachev 				 * to it anymore after disconnect so on next crtc to connector
952b843c749SSergey Zigachev 				 * reshuffle by UMD we will get into unwanted dc_sink release
953b843c749SSergey Zigachev 				 */
954b843c749SSergey Zigachev 				if (aconnector->dc_sink != aconnector->dc_em_sink)
955b843c749SSergey Zigachev 					dc_sink_release(aconnector->dc_sink);
956b843c749SSergey Zigachev 			}
957b843c749SSergey Zigachev 			aconnector->dc_sink = sink;
958b843c749SSergey Zigachev 			amdgpu_dm_add_sink_to_freesync_module(
959b843c749SSergey Zigachev 						connector, aconnector->edid);
960b843c749SSergey Zigachev 		} else {
961b843c749SSergey Zigachev 			amdgpu_dm_remove_sink_from_freesync_module(connector);
962b843c749SSergey Zigachev 			if (!aconnector->dc_sink)
963b843c749SSergey Zigachev 				aconnector->dc_sink = aconnector->dc_em_sink;
964b843c749SSergey Zigachev 			else if (aconnector->dc_sink != aconnector->dc_em_sink)
965b843c749SSergey Zigachev 				dc_sink_retain(aconnector->dc_sink);
966b843c749SSergey Zigachev 		}
967b843c749SSergey Zigachev 
968b843c749SSergey Zigachev 		mutex_unlock(&dev->mode_config.mutex);
969b843c749SSergey Zigachev 		return;
970b843c749SSergey Zigachev 	}
971b843c749SSergey Zigachev 
972b843c749SSergey Zigachev 	/*
973b843c749SSergey Zigachev 	 * TODO: temporary guard to look for proper fix
974b843c749SSergey Zigachev 	 * if this sink is MST sink, we should not do anything
975b843c749SSergey Zigachev 	 */
976b843c749SSergey Zigachev 	if (sink && sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
977b843c749SSergey Zigachev 		return;
978b843c749SSergey Zigachev 
979b843c749SSergey Zigachev 	if (aconnector->dc_sink == sink) {
980b843c749SSergey Zigachev 		/* We got a DP short pulse (Link Loss, DP CTS, etc...).
981b843c749SSergey Zigachev 		 * Do nothing!! */
982b843c749SSergey Zigachev 		DRM_DEBUG_DRIVER("DCHPD: connector_id=%d: dc_sink didn't change.\n",
983b843c749SSergey Zigachev 				aconnector->connector_id);
984b843c749SSergey Zigachev 		return;
985b843c749SSergey Zigachev 	}
986b843c749SSergey Zigachev 
987b843c749SSergey Zigachev 	DRM_DEBUG_DRIVER("DCHPD: connector_id=%d: Old sink=%p New sink=%p\n",
988b843c749SSergey Zigachev 		aconnector->connector_id, aconnector->dc_sink, sink);
989b843c749SSergey Zigachev 
990b843c749SSergey Zigachev 	mutex_lock(&dev->mode_config.mutex);
991b843c749SSergey Zigachev 
992b843c749SSergey Zigachev 	/* 1. Update status of the drm connector
993b843c749SSergey Zigachev 	 * 2. Send an event and let userspace tell us what to do */
994b843c749SSergey Zigachev 	if (sink) {
995b843c749SSergey Zigachev 		/* TODO: check if we still need the S3 mode update workaround.
996b843c749SSergey Zigachev 		 * If yes, put it here. */
997b843c749SSergey Zigachev 		if (aconnector->dc_sink)
998b843c749SSergey Zigachev 			amdgpu_dm_remove_sink_from_freesync_module(
999b843c749SSergey Zigachev 							connector);
1000b843c749SSergey Zigachev 
1001b843c749SSergey Zigachev 		aconnector->dc_sink = sink;
1002b843c749SSergey Zigachev 		if (sink->dc_edid.length == 0) {
1003b843c749SSergey Zigachev 			aconnector->edid = NULL;
1004b843c749SSergey Zigachev 		} else {
1005b843c749SSergey Zigachev 			aconnector->edid =
1006b843c749SSergey Zigachev 				(struct edid *) sink->dc_edid.raw_edid;
1007b843c749SSergey Zigachev 
1008b843c749SSergey Zigachev 
1009b843c749SSergey Zigachev 			drm_connector_update_edid_property(connector,
1010b843c749SSergey Zigachev 					aconnector->edid);
1011b843c749SSergey Zigachev 		}
1012b843c749SSergey Zigachev 		amdgpu_dm_add_sink_to_freesync_module(connector, aconnector->edid);
1013b843c749SSergey Zigachev 
1014b843c749SSergey Zigachev 	} else {
1015b843c749SSergey Zigachev 		amdgpu_dm_remove_sink_from_freesync_module(connector);
1016b843c749SSergey Zigachev 		drm_connector_update_edid_property(connector, NULL);
1017b843c749SSergey Zigachev 		aconnector->num_modes = 0;
1018b843c749SSergey Zigachev 		aconnector->dc_sink = NULL;
1019b843c749SSergey Zigachev 		aconnector->edid = NULL;
1020b843c749SSergey Zigachev 	}
1021b843c749SSergey Zigachev 
1022b843c749SSergey Zigachev 	mutex_unlock(&dev->mode_config.mutex);
1023b843c749SSergey Zigachev }
1024b843c749SSergey Zigachev 
handle_hpd_irq(void * param)1025b843c749SSergey Zigachev static void handle_hpd_irq(void *param)
1026b843c749SSergey Zigachev {
1027b843c749SSergey Zigachev 	struct amdgpu_dm_connector *aconnector = (struct amdgpu_dm_connector *)param;
1028b843c749SSergey Zigachev 	struct drm_connector *connector = &aconnector->base;
1029b843c749SSergey Zigachev 	struct drm_device *dev = connector->dev;
1030b843c749SSergey Zigachev 	enum dc_connection_type new_connection_type = dc_connection_none;
1031b843c749SSergey Zigachev 
1032b843c749SSergey Zigachev 	/* In case of failure or MST no need to update connector status or notify the OS
1033b843c749SSergey Zigachev 	 * since (for MST case) MST does this in it's own context.
1034b843c749SSergey Zigachev 	 */
1035b843c749SSergey Zigachev 	mutex_lock(&aconnector->hpd_lock);
1036b843c749SSergey Zigachev 
1037b843c749SSergey Zigachev 	if (aconnector->fake_enable)
1038b843c749SSergey Zigachev 		aconnector->fake_enable = false;
1039b843c749SSergey Zigachev 
1040b843c749SSergey Zigachev 	if (!dc_link_detect_sink(aconnector->dc_link, &new_connection_type))
1041b843c749SSergey Zigachev 		DRM_ERROR("KMS: Failed to detect connector\n");
1042b843c749SSergey Zigachev 
1043b843c749SSergey Zigachev 	if (aconnector->base.force && new_connection_type == dc_connection_none) {
1044b843c749SSergey Zigachev 		emulated_link_detect(aconnector->dc_link);
1045b843c749SSergey Zigachev 
1046b843c749SSergey Zigachev 
1047b843c749SSergey Zigachev 		drm_modeset_lock_all(dev);
1048b843c749SSergey Zigachev 		dm_restore_drm_connector_state(dev, connector);
1049b843c749SSergey Zigachev 		drm_modeset_unlock_all(dev);
1050b843c749SSergey Zigachev 
1051b843c749SSergey Zigachev 		if (aconnector->base.force == DRM_FORCE_UNSPECIFIED)
1052b843c749SSergey Zigachev 			drm_kms_helper_hotplug_event(dev);
1053b843c749SSergey Zigachev 
1054b843c749SSergey Zigachev 	} else if (dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD)) {
1055b843c749SSergey Zigachev 		amdgpu_dm_update_connector_after_detect(aconnector);
1056b843c749SSergey Zigachev 
1057b843c749SSergey Zigachev 
1058b843c749SSergey Zigachev 		drm_modeset_lock_all(dev);
1059b843c749SSergey Zigachev 		dm_restore_drm_connector_state(dev, connector);
1060b843c749SSergey Zigachev 		drm_modeset_unlock_all(dev);
1061b843c749SSergey Zigachev 
1062b843c749SSergey Zigachev 		if (aconnector->base.force == DRM_FORCE_UNSPECIFIED)
1063b843c749SSergey Zigachev 			drm_kms_helper_hotplug_event(dev);
1064b843c749SSergey Zigachev 	}
1065b843c749SSergey Zigachev 	mutex_unlock(&aconnector->hpd_lock);
1066b843c749SSergey Zigachev 
1067b843c749SSergey Zigachev }
1068b843c749SSergey Zigachev 
dm_handle_hpd_rx_irq(struct amdgpu_dm_connector * aconnector)1069b843c749SSergey Zigachev static void dm_handle_hpd_rx_irq(struct amdgpu_dm_connector *aconnector)
1070b843c749SSergey Zigachev {
1071b843c749SSergey Zigachev 	uint8_t esi[DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI] = { 0 };
1072b843c749SSergey Zigachev 	uint8_t dret;
1073b843c749SSergey Zigachev 	bool new_irq_handled = false;
1074b843c749SSergey Zigachev 	int dpcd_addr;
1075b843c749SSergey Zigachev 	int dpcd_bytes_to_read;
1076b843c749SSergey Zigachev 
1077b843c749SSergey Zigachev 	const int max_process_count = 30;
1078b843c749SSergey Zigachev 	int process_count = 0;
1079b843c749SSergey Zigachev 
1080b843c749SSergey Zigachev 	const struct dc_link_status *link_status = dc_link_get_status(aconnector->dc_link);
1081b843c749SSergey Zigachev 
1082b843c749SSergey Zigachev 	if (link_status->dpcd_caps->dpcd_rev.raw < 0x12) {
1083b843c749SSergey Zigachev 		dpcd_bytes_to_read = DP_LANE0_1_STATUS - DP_SINK_COUNT;
1084b843c749SSergey Zigachev 		/* DPCD 0x200 - 0x201 for downstream IRQ */
1085b843c749SSergey Zigachev 		dpcd_addr = DP_SINK_COUNT;
1086b843c749SSergey Zigachev 	} else {
1087b843c749SSergey Zigachev 		dpcd_bytes_to_read = DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI;
1088b843c749SSergey Zigachev 		/* DPCD 0x2002 - 0x2005 for downstream IRQ */
1089b843c749SSergey Zigachev 		dpcd_addr = DP_SINK_COUNT_ESI;
1090b843c749SSergey Zigachev 	}
1091b843c749SSergey Zigachev 
1092b843c749SSergey Zigachev 	dret = drm_dp_dpcd_read(
1093b843c749SSergey Zigachev 		&aconnector->dm_dp_aux.aux,
1094b843c749SSergey Zigachev 		dpcd_addr,
1095b843c749SSergey Zigachev 		esi,
1096b843c749SSergey Zigachev 		dpcd_bytes_to_read);
1097b843c749SSergey Zigachev 
1098b843c749SSergey Zigachev 	while (dret == dpcd_bytes_to_read &&
1099b843c749SSergey Zigachev 		process_count < max_process_count) {
1100b843c749SSergey Zigachev 		uint8_t retry;
1101b843c749SSergey Zigachev 		dret = 0;
1102b843c749SSergey Zigachev 
1103b843c749SSergey Zigachev 		process_count++;
1104b843c749SSergey Zigachev 
1105b843c749SSergey Zigachev 		DRM_DEBUG_DRIVER("ESI %02x %02x %02x\n", esi[0], esi[1], esi[2]);
1106b843c749SSergey Zigachev 		/* handle HPD short pulse irq */
1107b843c749SSergey Zigachev 		if (aconnector->mst_mgr.mst_state)
1108b843c749SSergey Zigachev 			drm_dp_mst_hpd_irq(
1109b843c749SSergey Zigachev 				&aconnector->mst_mgr,
1110b843c749SSergey Zigachev 				esi,
1111b843c749SSergey Zigachev 				&new_irq_handled);
1112b843c749SSergey Zigachev 
1113b843c749SSergey Zigachev 		if (new_irq_handled) {
1114b843c749SSergey Zigachev 			/* ACK at DPCD to notify down stream */
1115b843c749SSergey Zigachev 			const int ack_dpcd_bytes_to_write =
1116b843c749SSergey Zigachev 				dpcd_bytes_to_read - 1;
1117b843c749SSergey Zigachev 
1118b843c749SSergey Zigachev 			for (retry = 0; retry < 3; retry++) {
1119b843c749SSergey Zigachev 				uint8_t wret;
1120b843c749SSergey Zigachev 
1121b843c749SSergey Zigachev 				wret = drm_dp_dpcd_write(
1122b843c749SSergey Zigachev 					&aconnector->dm_dp_aux.aux,
1123b843c749SSergey Zigachev 					dpcd_addr + 1,
1124b843c749SSergey Zigachev 					&esi[1],
1125b843c749SSergey Zigachev 					ack_dpcd_bytes_to_write);
1126b843c749SSergey Zigachev 				if (wret == ack_dpcd_bytes_to_write)
1127b843c749SSergey Zigachev 					break;
1128b843c749SSergey Zigachev 			}
1129b843c749SSergey Zigachev 
1130b843c749SSergey Zigachev 			/* check if there is new irq to be handle */
1131b843c749SSergey Zigachev 			dret = drm_dp_dpcd_read(
1132b843c749SSergey Zigachev 				&aconnector->dm_dp_aux.aux,
1133b843c749SSergey Zigachev 				dpcd_addr,
1134b843c749SSergey Zigachev 				esi,
1135b843c749SSergey Zigachev 				dpcd_bytes_to_read);
1136b843c749SSergey Zigachev 
1137b843c749SSergey Zigachev 			new_irq_handled = false;
1138b843c749SSergey Zigachev 		} else {
1139b843c749SSergey Zigachev 			break;
1140b843c749SSergey Zigachev 		}
1141b843c749SSergey Zigachev 	}
1142b843c749SSergey Zigachev 
1143b843c749SSergey Zigachev 	if (process_count == max_process_count)
1144b843c749SSergey Zigachev 		DRM_DEBUG_DRIVER("Loop exceeded max iterations\n");
1145b843c749SSergey Zigachev }
1146b843c749SSergey Zigachev 
handle_hpd_rx_irq(void * param)1147b843c749SSergey Zigachev static void handle_hpd_rx_irq(void *param)
1148b843c749SSergey Zigachev {
1149b843c749SSergey Zigachev 	struct amdgpu_dm_connector *aconnector = (struct amdgpu_dm_connector *)param;
1150b843c749SSergey Zigachev 	struct drm_connector *connector = &aconnector->base;
1151b843c749SSergey Zigachev 	struct drm_device *dev = connector->dev;
1152b843c749SSergey Zigachev 	struct dc_link *dc_link = aconnector->dc_link;
1153b843c749SSergey Zigachev 	bool is_mst_root_connector = aconnector->mst_mgr.mst_state;
1154b843c749SSergey Zigachev 	enum dc_connection_type new_connection_type = dc_connection_none;
1155b843c749SSergey Zigachev 
1156b843c749SSergey Zigachev 	/* TODO:Temporary add mutex to protect hpd interrupt not have a gpio
1157b843c749SSergey Zigachev 	 * conflict, after implement i2c helper, this mutex should be
1158b843c749SSergey Zigachev 	 * retired.
1159b843c749SSergey Zigachev 	 */
1160b843c749SSergey Zigachev 	if (dc_link->type != dc_connection_mst_branch)
1161b843c749SSergey Zigachev 		mutex_lock(&aconnector->hpd_lock);
1162b843c749SSergey Zigachev 
1163b843c749SSergey Zigachev 	if (dc_link_handle_hpd_rx_irq(dc_link, NULL, NULL) &&
1164b843c749SSergey Zigachev 			!is_mst_root_connector) {
1165b843c749SSergey Zigachev 		/* Downstream Port status changed. */
1166b843c749SSergey Zigachev 		if (!dc_link_detect_sink(dc_link, &new_connection_type))
1167b843c749SSergey Zigachev 			DRM_ERROR("KMS: Failed to detect connector\n");
1168b843c749SSergey Zigachev 
1169b843c749SSergey Zigachev 		if (aconnector->base.force && new_connection_type == dc_connection_none) {
1170b843c749SSergey Zigachev 			emulated_link_detect(dc_link);
1171b843c749SSergey Zigachev 
1172b843c749SSergey Zigachev 			if (aconnector->fake_enable)
1173b843c749SSergey Zigachev 				aconnector->fake_enable = false;
1174b843c749SSergey Zigachev 
1175b843c749SSergey Zigachev 			amdgpu_dm_update_connector_after_detect(aconnector);
1176b843c749SSergey Zigachev 
1177b843c749SSergey Zigachev 
1178b843c749SSergey Zigachev 			drm_modeset_lock_all(dev);
1179b843c749SSergey Zigachev 			dm_restore_drm_connector_state(dev, connector);
1180b843c749SSergey Zigachev 			drm_modeset_unlock_all(dev);
1181b843c749SSergey Zigachev 
1182b843c749SSergey Zigachev 			drm_kms_helper_hotplug_event(dev);
1183b843c749SSergey Zigachev 		} else if (dc_link_detect(dc_link, DETECT_REASON_HPDRX)) {
1184b843c749SSergey Zigachev 
1185b843c749SSergey Zigachev 			if (aconnector->fake_enable)
1186b843c749SSergey Zigachev 				aconnector->fake_enable = false;
1187b843c749SSergey Zigachev 
1188b843c749SSergey Zigachev 			amdgpu_dm_update_connector_after_detect(aconnector);
1189b843c749SSergey Zigachev 
1190b843c749SSergey Zigachev 
1191b843c749SSergey Zigachev 			drm_modeset_lock_all(dev);
1192b843c749SSergey Zigachev 			dm_restore_drm_connector_state(dev, connector);
1193b843c749SSergey Zigachev 			drm_modeset_unlock_all(dev);
1194b843c749SSergey Zigachev 
1195b843c749SSergey Zigachev 			drm_kms_helper_hotplug_event(dev);
1196b843c749SSergey Zigachev 		}
1197b843c749SSergey Zigachev 	}
1198b843c749SSergey Zigachev 	if ((dc_link->cur_link_settings.lane_count != LANE_COUNT_UNKNOWN) ||
1199b843c749SSergey Zigachev 	    (dc_link->type == dc_connection_mst_branch))
1200b843c749SSergey Zigachev 		dm_handle_hpd_rx_irq(aconnector);
1201b843c749SSergey Zigachev 
1202b843c749SSergey Zigachev 	if (dc_link->type != dc_connection_mst_branch)
1203b843c749SSergey Zigachev 		mutex_unlock(&aconnector->hpd_lock);
1204b843c749SSergey Zigachev }
1205b843c749SSergey Zigachev 
register_hpd_handlers(struct amdgpu_device * adev)1206b843c749SSergey Zigachev static void register_hpd_handlers(struct amdgpu_device *adev)
1207b843c749SSergey Zigachev {
1208b843c749SSergey Zigachev 	struct drm_device *dev = adev->ddev;
1209b843c749SSergey Zigachev 	struct drm_connector *connector;
1210b843c749SSergey Zigachev 	struct amdgpu_dm_connector *aconnector;
1211b843c749SSergey Zigachev 	const struct dc_link *dc_link;
1212b843c749SSergey Zigachev 	struct dc_interrupt_params int_params = {0};
1213b843c749SSergey Zigachev 
1214b843c749SSergey Zigachev 	int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
1215b843c749SSergey Zigachev 	int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
1216b843c749SSergey Zigachev 
1217b843c749SSergey Zigachev 	list_for_each_entry(connector,
1218b843c749SSergey Zigachev 			&dev->mode_config.connector_list, head)	{
1219b843c749SSergey Zigachev 
1220b843c749SSergey Zigachev 		aconnector = to_amdgpu_dm_connector(connector);
1221b843c749SSergey Zigachev 		dc_link = aconnector->dc_link;
1222b843c749SSergey Zigachev 
1223b843c749SSergey Zigachev 		if (DC_IRQ_SOURCE_INVALID != dc_link->irq_source_hpd) {
1224b843c749SSergey Zigachev 			int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
1225b843c749SSergey Zigachev 			int_params.irq_source = dc_link->irq_source_hpd;
1226b843c749SSergey Zigachev 
1227b843c749SSergey Zigachev 			amdgpu_dm_irq_register_interrupt(adev, &int_params,
1228b843c749SSergey Zigachev 					handle_hpd_irq,
1229b843c749SSergey Zigachev 					(void *) aconnector);
1230b843c749SSergey Zigachev 		}
1231b843c749SSergey Zigachev 
1232b843c749SSergey Zigachev 		if (DC_IRQ_SOURCE_INVALID != dc_link->irq_source_hpd_rx) {
1233b843c749SSergey Zigachev 
1234b843c749SSergey Zigachev 			/* Also register for DP short pulse (hpd_rx). */
1235b843c749SSergey Zigachev 			int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
1236b843c749SSergey Zigachev 			int_params.irq_source =	dc_link->irq_source_hpd_rx;
1237b843c749SSergey Zigachev 
1238b843c749SSergey Zigachev 			amdgpu_dm_irq_register_interrupt(adev, &int_params,
1239b843c749SSergey Zigachev 					handle_hpd_rx_irq,
1240b843c749SSergey Zigachev 					(void *) aconnector);
1241b843c749SSergey Zigachev 		}
1242b843c749SSergey Zigachev 	}
1243b843c749SSergey Zigachev }
1244b843c749SSergey Zigachev 
1245b843c749SSergey Zigachev /* Register IRQ sources and initialize IRQ callbacks */
dce110_register_irq_handlers(struct amdgpu_device * adev)1246b843c749SSergey Zigachev static int dce110_register_irq_handlers(struct amdgpu_device *adev)
1247b843c749SSergey Zigachev {
1248b843c749SSergey Zigachev 	struct dc *dc = adev->dm.dc;
1249b843c749SSergey Zigachev 	struct common_irq_params *c_irq_params;
1250b843c749SSergey Zigachev 	struct dc_interrupt_params int_params = {0};
1251b843c749SSergey Zigachev 	int r;
1252b843c749SSergey Zigachev 	int i;
1253b843c749SSergey Zigachev 	unsigned client_id = AMDGPU_IH_CLIENTID_LEGACY;
1254b843c749SSergey Zigachev 
1255b843c749SSergey Zigachev 	if (adev->asic_type == CHIP_VEGA10 ||
1256b843c749SSergey Zigachev 	    adev->asic_type == CHIP_VEGA12 ||
1257b843c749SSergey Zigachev 	    adev->asic_type == CHIP_VEGA20 ||
1258b843c749SSergey Zigachev 	    adev->asic_type == CHIP_RAVEN)
1259b843c749SSergey Zigachev 		client_id = SOC15_IH_CLIENTID_DCE;
1260b843c749SSergey Zigachev 
1261b843c749SSergey Zigachev 	int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
1262b843c749SSergey Zigachev 	int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
1263b843c749SSergey Zigachev 
1264b843c749SSergey Zigachev 	/* Actions of amdgpu_irq_add_id():
1265b843c749SSergey Zigachev 	 * 1. Register a set() function with base driver.
1266b843c749SSergey Zigachev 	 *    Base driver will call set() function to enable/disable an
1267b843c749SSergey Zigachev 	 *    interrupt in DC hardware.
1268b843c749SSergey Zigachev 	 * 2. Register amdgpu_dm_irq_handler().
1269b843c749SSergey Zigachev 	 *    Base driver will call amdgpu_dm_irq_handler() for ALL interrupts
1270b843c749SSergey Zigachev 	 *    coming from DC hardware.
1271b843c749SSergey Zigachev 	 *    amdgpu_dm_irq_handler() will re-direct the interrupt to DC
1272b843c749SSergey Zigachev 	 *    for acknowledging and handling. */
1273b843c749SSergey Zigachev 
1274b843c749SSergey Zigachev 	/* Use VBLANK interrupt */
1275b843c749SSergey Zigachev 	for (i = VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0; i <= VISLANDS30_IV_SRCID_D6_VERTICAL_INTERRUPT0; i++) {
1276b843c749SSergey Zigachev 		r = amdgpu_irq_add_id(adev, client_id, i, &adev->crtc_irq);
1277b843c749SSergey Zigachev 		if (r) {
1278b843c749SSergey Zigachev 			DRM_ERROR("Failed to add crtc irq id!\n");
1279b843c749SSergey Zigachev 			return r;
1280b843c749SSergey Zigachev 		}
1281b843c749SSergey Zigachev 
1282b843c749SSergey Zigachev 		int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
1283b843c749SSergey Zigachev 		int_params.irq_source =
1284b843c749SSergey Zigachev 			dc_interrupt_to_irq_source(dc, i, 0);
1285b843c749SSergey Zigachev 
1286b843c749SSergey Zigachev 		c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1];
1287b843c749SSergey Zigachev 
1288b843c749SSergey Zigachev 		c_irq_params->adev = adev;
1289b843c749SSergey Zigachev 		c_irq_params->irq_src = int_params.irq_source;
1290b843c749SSergey Zigachev 
1291b843c749SSergey Zigachev 		amdgpu_dm_irq_register_interrupt(adev, &int_params,
1292b843c749SSergey Zigachev 				dm_crtc_high_irq, c_irq_params);
1293b843c749SSergey Zigachev 	}
1294b843c749SSergey Zigachev 
1295b843c749SSergey Zigachev 	/* Use GRPH_PFLIP interrupt */
1296b843c749SSergey Zigachev 	for (i = VISLANDS30_IV_SRCID_D1_GRPH_PFLIP;
1297b843c749SSergey Zigachev 			i <= VISLANDS30_IV_SRCID_D6_GRPH_PFLIP; i += 2) {
1298b843c749SSergey Zigachev 		r = amdgpu_irq_add_id(adev, client_id, i, &adev->pageflip_irq);
1299b843c749SSergey Zigachev 		if (r) {
1300b843c749SSergey Zigachev 			DRM_ERROR("Failed to add page flip irq id!\n");
1301b843c749SSergey Zigachev 			return r;
1302b843c749SSergey Zigachev 		}
1303b843c749SSergey Zigachev 
1304b843c749SSergey Zigachev 		int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
1305b843c749SSergey Zigachev 		int_params.irq_source =
1306b843c749SSergey Zigachev 			dc_interrupt_to_irq_source(dc, i, 0);
1307b843c749SSergey Zigachev 
1308b843c749SSergey Zigachev 		c_irq_params = &adev->dm.pflip_params[int_params.irq_source - DC_IRQ_SOURCE_PFLIP_FIRST];
1309b843c749SSergey Zigachev 
1310b843c749SSergey Zigachev 		c_irq_params->adev = adev;
1311b843c749SSergey Zigachev 		c_irq_params->irq_src = int_params.irq_source;
1312b843c749SSergey Zigachev 
1313b843c749SSergey Zigachev 		amdgpu_dm_irq_register_interrupt(adev, &int_params,
1314b843c749SSergey Zigachev 				dm_pflip_high_irq, c_irq_params);
1315b843c749SSergey Zigachev 
1316b843c749SSergey Zigachev 	}
1317b843c749SSergey Zigachev 
1318b843c749SSergey Zigachev 	/* HPD */
1319b843c749SSergey Zigachev 	r = amdgpu_irq_add_id(adev, client_id,
1320b843c749SSergey Zigachev 			VISLANDS30_IV_SRCID_HOTPLUG_DETECT_A, &adev->hpd_irq);
1321b843c749SSergey Zigachev 	if (r) {
1322b843c749SSergey Zigachev 		DRM_ERROR("Failed to add hpd irq id!\n");
1323b843c749SSergey Zigachev 		return r;
1324b843c749SSergey Zigachev 	}
1325b843c749SSergey Zigachev 
1326b843c749SSergey Zigachev 	register_hpd_handlers(adev);
1327b843c749SSergey Zigachev 
1328b843c749SSergey Zigachev 	return 0;
1329b843c749SSergey Zigachev }
1330b843c749SSergey Zigachev 
1331b843c749SSergey Zigachev #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
1332b843c749SSergey Zigachev /* Register IRQ sources and initialize IRQ callbacks */
dcn10_register_irq_handlers(struct amdgpu_device * adev)1333b843c749SSergey Zigachev static int dcn10_register_irq_handlers(struct amdgpu_device *adev)
1334b843c749SSergey Zigachev {
1335b843c749SSergey Zigachev 	struct dc *dc = adev->dm.dc;
1336b843c749SSergey Zigachev 	struct common_irq_params *c_irq_params;
1337b843c749SSergey Zigachev 	struct dc_interrupt_params int_params = {0};
1338b843c749SSergey Zigachev 	int r;
1339b843c749SSergey Zigachev 	int i;
1340b843c749SSergey Zigachev 
1341b843c749SSergey Zigachev 	int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
1342b843c749SSergey Zigachev 	int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
1343b843c749SSergey Zigachev 
1344b843c749SSergey Zigachev 	/* Actions of amdgpu_irq_add_id():
1345b843c749SSergey Zigachev 	 * 1. Register a set() function with base driver.
1346b843c749SSergey Zigachev 	 *    Base driver will call set() function to enable/disable an
1347b843c749SSergey Zigachev 	 *    interrupt in DC hardware.
1348b843c749SSergey Zigachev 	 * 2. Register amdgpu_dm_irq_handler().
1349b843c749SSergey Zigachev 	 *    Base driver will call amdgpu_dm_irq_handler() for ALL interrupts
1350b843c749SSergey Zigachev 	 *    coming from DC hardware.
1351b843c749SSergey Zigachev 	 *    amdgpu_dm_irq_handler() will re-direct the interrupt to DC
1352b843c749SSergey Zigachev 	 *    for acknowledging and handling.
1353b843c749SSergey Zigachev 	 * */
1354b843c749SSergey Zigachev 
1355b843c749SSergey Zigachev 	/* Use VSTARTUP interrupt */
1356b843c749SSergey Zigachev 	for (i = DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP;
1357b843c749SSergey Zigachev 			i <= DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP + adev->mode_info.num_crtc - 1;
1358b843c749SSergey Zigachev 			i++) {
1359b843c749SSergey Zigachev 		r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->crtc_irq);
1360b843c749SSergey Zigachev 
1361b843c749SSergey Zigachev 		if (r) {
1362b843c749SSergey Zigachev 			DRM_ERROR("Failed to add crtc irq id!\n");
1363b843c749SSergey Zigachev 			return r;
1364b843c749SSergey Zigachev 		}
1365b843c749SSergey Zigachev 
1366b843c749SSergey Zigachev 		int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
1367b843c749SSergey Zigachev 		int_params.irq_source =
1368b843c749SSergey Zigachev 			dc_interrupt_to_irq_source(dc, i, 0);
1369b843c749SSergey Zigachev 
1370b843c749SSergey Zigachev 		c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1];
1371b843c749SSergey Zigachev 
1372b843c749SSergey Zigachev 		c_irq_params->adev = adev;
1373b843c749SSergey Zigachev 		c_irq_params->irq_src = int_params.irq_source;
1374b843c749SSergey Zigachev 
1375b843c749SSergey Zigachev 		amdgpu_dm_irq_register_interrupt(adev, &int_params,
1376b843c749SSergey Zigachev 				dm_crtc_high_irq, c_irq_params);
1377b843c749SSergey Zigachev 	}
1378b843c749SSergey Zigachev 
1379b843c749SSergey Zigachev 	/* Use GRPH_PFLIP interrupt */
1380b843c749SSergey Zigachev 	for (i = DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT;
1381b843c749SSergey Zigachev 			i <= DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT + adev->mode_info.num_crtc - 1;
1382b843c749SSergey Zigachev 			i++) {
1383b843c749SSergey Zigachev 		r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->pageflip_irq);
1384b843c749SSergey Zigachev 		if (r) {
1385b843c749SSergey Zigachev 			DRM_ERROR("Failed to add page flip irq id!\n");
1386b843c749SSergey Zigachev 			return r;
1387b843c749SSergey Zigachev 		}
1388b843c749SSergey Zigachev 
1389b843c749SSergey Zigachev 		int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
1390b843c749SSergey Zigachev 		int_params.irq_source =
1391b843c749SSergey Zigachev 			dc_interrupt_to_irq_source(dc, i, 0);
1392b843c749SSergey Zigachev 
1393b843c749SSergey Zigachev 		c_irq_params = &adev->dm.pflip_params[int_params.irq_source - DC_IRQ_SOURCE_PFLIP_FIRST];
1394b843c749SSergey Zigachev 
1395b843c749SSergey Zigachev 		c_irq_params->adev = adev;
1396b843c749SSergey Zigachev 		c_irq_params->irq_src = int_params.irq_source;
1397b843c749SSergey Zigachev 
1398b843c749SSergey Zigachev 		amdgpu_dm_irq_register_interrupt(adev, &int_params,
1399b843c749SSergey Zigachev 				dm_pflip_high_irq, c_irq_params);
1400b843c749SSergey Zigachev 
1401b843c749SSergey Zigachev 	}
1402b843c749SSergey Zigachev 
1403b843c749SSergey Zigachev 	/* HPD */
1404b843c749SSergey Zigachev 	r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, DCN_1_0__SRCID__DC_HPD1_INT,
1405b843c749SSergey Zigachev 			&adev->hpd_irq);
1406b843c749SSergey Zigachev 	if (r) {
1407b843c749SSergey Zigachev 		DRM_ERROR("Failed to add hpd irq id!\n");
1408b843c749SSergey Zigachev 		return r;
1409b843c749SSergey Zigachev 	}
1410b843c749SSergey Zigachev 
1411b843c749SSergey Zigachev 	register_hpd_handlers(adev);
1412b843c749SSergey Zigachev 
1413b843c749SSergey Zigachev 	return 0;
1414b843c749SSergey Zigachev }
1415b843c749SSergey Zigachev #endif
1416b843c749SSergey Zigachev 
amdgpu_dm_mode_config_init(struct amdgpu_device * adev)1417b843c749SSergey Zigachev static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
1418b843c749SSergey Zigachev {
1419b843c749SSergey Zigachev 	int r;
1420b843c749SSergey Zigachev 
1421b843c749SSergey Zigachev 	adev->mode_info.mode_config_initialized = true;
1422b843c749SSergey Zigachev 
1423b843c749SSergey Zigachev 	adev->ddev->mode_config.funcs = (void *)&amdgpu_dm_mode_funcs;
1424b843c749SSergey Zigachev 	adev->ddev->mode_config.helper_private = &amdgpu_dm_mode_config_helperfuncs;
1425b843c749SSergey Zigachev 
1426b843c749SSergey Zigachev 	adev->ddev->mode_config.max_width = 16384;
1427b843c749SSergey Zigachev 	adev->ddev->mode_config.max_height = 16384;
1428b843c749SSergey Zigachev 
1429b843c749SSergey Zigachev 	adev->ddev->mode_config.preferred_depth = 24;
1430b843c749SSergey Zigachev 	adev->ddev->mode_config.prefer_shadow = 1;
1431b843c749SSergey Zigachev 	/* indicate support of immediate flip */
1432b843c749SSergey Zigachev 	adev->ddev->mode_config.async_page_flip = true;
1433b843c749SSergey Zigachev 
1434b843c749SSergey Zigachev 	adev->ddev->mode_config.fb_base = adev->gmc.aper_base;
1435b843c749SSergey Zigachev 
1436b843c749SSergey Zigachev 	r = amdgpu_display_modeset_create_props(adev);
1437b843c749SSergey Zigachev 	if (r)
1438b843c749SSergey Zigachev 		return r;
1439b843c749SSergey Zigachev 
1440b843c749SSergey Zigachev 	return 0;
1441b843c749SSergey Zigachev }
1442b843c749SSergey Zigachev 
1443b843c749SSergey Zigachev #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\
1444b843c749SSergey Zigachev 	defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
1445b843c749SSergey Zigachev 
1446*78973132SSergey Zigachev #if 0
1447b843c749SSergey Zigachev static int amdgpu_dm_backlight_update_status(struct backlight_device *bd)
1448b843c749SSergey Zigachev {
1449b843c749SSergey Zigachev 	struct amdgpu_display_manager *dm = bl_get_data(bd);
1450b843c749SSergey Zigachev 
1451b843c749SSergey Zigachev 	if (dc_link_set_backlight_level(dm->backlight_link,
1452b843c749SSergey Zigachev 			bd->props.brightness, 0, 0))
1453b843c749SSergey Zigachev 		return 0;
1454b843c749SSergey Zigachev 	else
1455b843c749SSergey Zigachev 		return 1;
1456b843c749SSergey Zigachev }
1457b843c749SSergey Zigachev 
1458b843c749SSergey Zigachev static int amdgpu_dm_backlight_get_brightness(struct backlight_device *bd)
1459b843c749SSergey Zigachev {
1460b843c749SSergey Zigachev 	struct amdgpu_display_manager *dm = bl_get_data(bd);
1461b843c749SSergey Zigachev 	int ret = dc_link_get_backlight_level(dm->backlight_link);
1462b843c749SSergey Zigachev 
1463b843c749SSergey Zigachev 	if (ret == DC_ERROR_UNEXPECTED)
1464b843c749SSergey Zigachev 		return bd->props.brightness;
1465b843c749SSergey Zigachev 	return ret;
1466b843c749SSergey Zigachev }
1467b843c749SSergey Zigachev 
1468b843c749SSergey Zigachev static const struct backlight_ops amdgpu_dm_backlight_ops = {
1469b843c749SSergey Zigachev 	.options = BL_CORE_SUSPENDRESUME,
1470b843c749SSergey Zigachev 	.get_brightness = amdgpu_dm_backlight_get_brightness,
1471b843c749SSergey Zigachev 	.update_status	= amdgpu_dm_backlight_update_status,
1472b843c749SSergey Zigachev };
1473*78973132SSergey Zigachev #endif
1474b843c749SSergey Zigachev 
1475b843c749SSergey Zigachev static void
amdgpu_dm_register_backlight_device(struct amdgpu_display_manager * dm)1476b843c749SSergey Zigachev amdgpu_dm_register_backlight_device(struct amdgpu_display_manager *dm)
1477b843c749SSergey Zigachev {
1478*78973132SSergey Zigachev #if 0
1479b843c749SSergey Zigachev 	char bl_name[16];
1480b843c749SSergey Zigachev 	struct backlight_properties props = { 0 };
1481b843c749SSergey Zigachev 
1482b843c749SSergey Zigachev 	props.max_brightness = AMDGPU_MAX_BL_LEVEL;
1483b843c749SSergey Zigachev 	props.brightness = AMDGPU_MAX_BL_LEVEL;
1484b843c749SSergey Zigachev 	props.type = BACKLIGHT_RAW;
1485b843c749SSergey Zigachev 
1486b843c749SSergey Zigachev 	snprintf(bl_name, sizeof(bl_name), "amdgpu_bl%d",
1487b843c749SSergey Zigachev 			dm->adev->ddev->primary->index);
1488b843c749SSergey Zigachev 
1489b843c749SSergey Zigachev 	dm->backlight_dev = backlight_device_register(bl_name,
1490b843c749SSergey Zigachev 			dm->adev->ddev->dev,
1491b843c749SSergey Zigachev 			dm,
1492b843c749SSergey Zigachev 			&amdgpu_dm_backlight_ops,
1493b843c749SSergey Zigachev 			&props);
1494b843c749SSergey Zigachev 
1495b843c749SSergey Zigachev 	if (IS_ERR(dm->backlight_dev))
1496b843c749SSergey Zigachev 		DRM_ERROR("DM: Backlight registration failed!\n");
1497b843c749SSergey Zigachev 	else
1498b843c749SSergey Zigachev 		DRM_DEBUG_DRIVER("DM: Registered Backlight device: %s\n", bl_name);
1499*78973132SSergey Zigachev #endif
1500b843c749SSergey Zigachev }
1501b843c749SSergey Zigachev 
1502b843c749SSergey Zigachev #endif
1503b843c749SSergey Zigachev 
initialize_plane(struct amdgpu_display_manager * dm,struct amdgpu_mode_info * mode_info,int plane_id)1504b843c749SSergey Zigachev static int initialize_plane(struct amdgpu_display_manager *dm,
1505b843c749SSergey Zigachev 			     struct amdgpu_mode_info *mode_info,
1506b843c749SSergey Zigachev 			     int plane_id)
1507b843c749SSergey Zigachev {
1508b843c749SSergey Zigachev 	struct amdgpu_plane *plane;
1509b843c749SSergey Zigachev 	unsigned long possible_crtcs;
1510b843c749SSergey Zigachev 	int ret = 0;
1511b843c749SSergey Zigachev 
1512b843c749SSergey Zigachev 	plane = kzalloc(sizeof(struct amdgpu_plane), GFP_KERNEL);
1513b843c749SSergey Zigachev 	mode_info->planes[plane_id] = plane;
1514b843c749SSergey Zigachev 
1515b843c749SSergey Zigachev 	if (!plane) {
1516b843c749SSergey Zigachev 		DRM_ERROR("KMS: Failed to allocate plane\n");
1517b843c749SSergey Zigachev 		return -ENOMEM;
1518b843c749SSergey Zigachev 	}
1519b843c749SSergey Zigachev 	plane->base.type = mode_info->plane_type[plane_id];
1520b843c749SSergey Zigachev 
1521b843c749SSergey Zigachev 	/*
1522b843c749SSergey Zigachev 	 * HACK: IGT tests expect that each plane can only have one
1523b843c749SSergey Zigachev 	 * one possible CRTC. For now, set one CRTC for each
1524b843c749SSergey Zigachev 	 * plane that is not an underlay, but still allow multiple
1525b843c749SSergey Zigachev 	 * CRTCs for underlay planes.
1526b843c749SSergey Zigachev 	 */
1527b843c749SSergey Zigachev 	possible_crtcs = 1 << plane_id;
1528b843c749SSergey Zigachev 	if (plane_id >= dm->dc->caps.max_streams)
1529b843c749SSergey Zigachev 		possible_crtcs = 0xff;
1530b843c749SSergey Zigachev 
1531b843c749SSergey Zigachev 	ret = amdgpu_dm_plane_init(dm, mode_info->planes[plane_id], possible_crtcs);
1532b843c749SSergey Zigachev 
1533b843c749SSergey Zigachev 	if (ret) {
1534b843c749SSergey Zigachev 		DRM_ERROR("KMS: Failed to initialize plane\n");
1535b843c749SSergey Zigachev 		return ret;
1536b843c749SSergey Zigachev 	}
1537b843c749SSergey Zigachev 
1538b843c749SSergey Zigachev 	return ret;
1539b843c749SSergey Zigachev }
1540b843c749SSergey Zigachev 
1541b843c749SSergey Zigachev 
register_backlight_device(struct amdgpu_display_manager * dm,struct dc_link * link)1542b843c749SSergey Zigachev static void register_backlight_device(struct amdgpu_display_manager *dm,
1543b843c749SSergey Zigachev 				      struct dc_link *link)
1544b843c749SSergey Zigachev {
1545b843c749SSergey Zigachev #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\
1546b843c749SSergey Zigachev 	defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
1547b843c749SSergey Zigachev 
1548b843c749SSergey Zigachev 	if ((link->connector_signal & (SIGNAL_TYPE_EDP | SIGNAL_TYPE_LVDS)) &&
1549b843c749SSergey Zigachev 	    link->type != dc_connection_none) {
1550b843c749SSergey Zigachev 		/* Event if registration failed, we should continue with
1551b843c749SSergey Zigachev 		 * DM initialization because not having a backlight control
1552b843c749SSergey Zigachev 		 * is better then a black screen.
1553b843c749SSergey Zigachev 		 */
1554b843c749SSergey Zigachev 		amdgpu_dm_register_backlight_device(dm);
1555b843c749SSergey Zigachev 
1556b843c749SSergey Zigachev 		if (dm->backlight_dev)
1557b843c749SSergey Zigachev 			dm->backlight_link = link;
1558b843c749SSergey Zigachev 	}
1559b843c749SSergey Zigachev #endif
1560b843c749SSergey Zigachev }
1561b843c749SSergey Zigachev 
1562b843c749SSergey Zigachev 
1563b843c749SSergey Zigachev /* In this architecture, the association
1564b843c749SSergey Zigachev  * connector -> encoder -> crtc
1565b843c749SSergey Zigachev  * id not really requried. The crtc and connector will hold the
1566b843c749SSergey Zigachev  * display_index as an abstraction to use with DAL component
1567b843c749SSergey Zigachev  *
1568b843c749SSergey Zigachev  * Returns 0 on success
1569b843c749SSergey Zigachev  */
amdgpu_dm_initialize_drm_device(struct amdgpu_device * adev)1570b843c749SSergey Zigachev static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
1571b843c749SSergey Zigachev {
1572b843c749SSergey Zigachev 	struct amdgpu_display_manager *dm = &adev->dm;
1573b843c749SSergey Zigachev 	int32_t i;
1574b843c749SSergey Zigachev 	struct amdgpu_dm_connector *aconnector = NULL;
1575b843c749SSergey Zigachev 	struct amdgpu_encoder *aencoder = NULL;
1576b843c749SSergey Zigachev 	struct amdgpu_mode_info *mode_info = &adev->mode_info;
1577b843c749SSergey Zigachev 	uint32_t link_cnt;
1578b843c749SSergey Zigachev 	int32_t total_overlay_planes, total_primary_planes;
1579b843c749SSergey Zigachev 	enum dc_connection_type new_connection_type = dc_connection_none;
1580b843c749SSergey Zigachev 
1581b843c749SSergey Zigachev 	link_cnt = dm->dc->caps.max_links;
1582b843c749SSergey Zigachev 	if (amdgpu_dm_mode_config_init(dm->adev)) {
1583b843c749SSergey Zigachev 		DRM_ERROR("DM: Failed to initialize mode config\n");
1584b843c749SSergey Zigachev 		return -1;
1585b843c749SSergey Zigachev 	}
1586b843c749SSergey Zigachev 
1587b843c749SSergey Zigachev 	/* Identify the number of planes to be initialized */
1588b843c749SSergey Zigachev 	total_overlay_planes = dm->dc->caps.max_slave_planes;
1589b843c749SSergey Zigachev 	total_primary_planes = dm->dc->caps.max_planes - dm->dc->caps.max_slave_planes;
1590b843c749SSergey Zigachev 
1591b843c749SSergey Zigachev 	/* First initialize overlay planes, index starting after primary planes */
1592b843c749SSergey Zigachev 	for (i = (total_overlay_planes - 1); i >= 0; i--) {
1593b843c749SSergey Zigachev 		if (initialize_plane(dm, mode_info, (total_primary_planes + i))) {
1594b843c749SSergey Zigachev 			DRM_ERROR("KMS: Failed to initialize overlay plane\n");
1595b843c749SSergey Zigachev 			goto fail;
1596b843c749SSergey Zigachev 		}
1597b843c749SSergey Zigachev 	}
1598b843c749SSergey Zigachev 
1599b843c749SSergey Zigachev 	/* Initialize primary planes */
1600b843c749SSergey Zigachev 	for (i = (total_primary_planes - 1); i >= 0; i--) {
1601b843c749SSergey Zigachev 		if (initialize_plane(dm, mode_info, i)) {
1602b843c749SSergey Zigachev 			DRM_ERROR("KMS: Failed to initialize primary plane\n");
1603b843c749SSergey Zigachev 			goto fail;
1604b843c749SSergey Zigachev 		}
1605b843c749SSergey Zigachev 	}
1606b843c749SSergey Zigachev 
1607b843c749SSergey Zigachev 	for (i = 0; i < dm->dc->caps.max_streams; i++)
1608b843c749SSergey Zigachev 		if (amdgpu_dm_crtc_init(dm, &mode_info->planes[i]->base, i)) {
1609b843c749SSergey Zigachev 			DRM_ERROR("KMS: Failed to initialize crtc\n");
1610b843c749SSergey Zigachev 			goto fail;
1611b843c749SSergey Zigachev 		}
1612b843c749SSergey Zigachev 
1613b843c749SSergey Zigachev 	dm->display_indexes_num = dm->dc->caps.max_streams;
1614b843c749SSergey Zigachev 
1615b843c749SSergey Zigachev 	/* loops over all connectors on the board */
1616b843c749SSergey Zigachev 	for (i = 0; i < link_cnt; i++) {
1617b843c749SSergey Zigachev 		struct dc_link *link = NULL;
1618b843c749SSergey Zigachev 
1619b843c749SSergey Zigachev 		if (i > AMDGPU_DM_MAX_DISPLAY_INDEX) {
1620b843c749SSergey Zigachev 			DRM_ERROR(
1621b843c749SSergey Zigachev 				"KMS: Cannot support more than %d display indexes\n",
1622b843c749SSergey Zigachev 					AMDGPU_DM_MAX_DISPLAY_INDEX);
1623b843c749SSergey Zigachev 			continue;
1624b843c749SSergey Zigachev 		}
1625b843c749SSergey Zigachev 
1626b843c749SSergey Zigachev 		aconnector = kzalloc(sizeof(*aconnector), GFP_KERNEL);
1627b843c749SSergey Zigachev 		if (!aconnector)
1628b843c749SSergey Zigachev 			goto fail;
1629b843c749SSergey Zigachev 
1630b843c749SSergey Zigachev 		aencoder = kzalloc(sizeof(*aencoder), GFP_KERNEL);
1631b843c749SSergey Zigachev 		if (!aencoder)
1632b843c749SSergey Zigachev 			goto fail;
1633b843c749SSergey Zigachev 
1634b843c749SSergey Zigachev 		if (amdgpu_dm_encoder_init(dm->ddev, aencoder, i)) {
1635b843c749SSergey Zigachev 			DRM_ERROR("KMS: Failed to initialize encoder\n");
1636b843c749SSergey Zigachev 			goto fail;
1637b843c749SSergey Zigachev 		}
1638b843c749SSergey Zigachev 
1639b843c749SSergey Zigachev 		if (amdgpu_dm_connector_init(dm, aconnector, i, aencoder)) {
1640b843c749SSergey Zigachev 			DRM_ERROR("KMS: Failed to initialize connector\n");
1641b843c749SSergey Zigachev 			goto fail;
1642b843c749SSergey Zigachev 		}
1643b843c749SSergey Zigachev 
1644b843c749SSergey Zigachev 		link = dc_get_link_at_index(dm->dc, i);
1645b843c749SSergey Zigachev 
1646b843c749SSergey Zigachev 		if (!dc_link_detect_sink(link, &new_connection_type))
1647b843c749SSergey Zigachev 			DRM_ERROR("KMS: Failed to detect connector\n");
1648b843c749SSergey Zigachev 
1649b843c749SSergey Zigachev 		if (aconnector->base.force && new_connection_type == dc_connection_none) {
1650b843c749SSergey Zigachev 			emulated_link_detect(link);
1651b843c749SSergey Zigachev 			amdgpu_dm_update_connector_after_detect(aconnector);
1652b843c749SSergey Zigachev 
1653b843c749SSergey Zigachev 		} else if (dc_link_detect(link, DETECT_REASON_BOOT)) {
1654b843c749SSergey Zigachev 			amdgpu_dm_update_connector_after_detect(aconnector);
1655b843c749SSergey Zigachev 			register_backlight_device(dm, link);
1656b843c749SSergey Zigachev 		}
1657b843c749SSergey Zigachev 
1658b843c749SSergey Zigachev 
1659b843c749SSergey Zigachev 	}
1660b843c749SSergey Zigachev 
1661b843c749SSergey Zigachev 	/* Software is initialized. Now we can register interrupt handlers. */
1662b843c749SSergey Zigachev 	switch (adev->asic_type) {
1663b843c749SSergey Zigachev 	case CHIP_BONAIRE:
1664b843c749SSergey Zigachev 	case CHIP_HAWAII:
1665b843c749SSergey Zigachev 	case CHIP_KAVERI:
1666b843c749SSergey Zigachev 	case CHIP_KABINI:
1667b843c749SSergey Zigachev 	case CHIP_MULLINS:
1668b843c749SSergey Zigachev 	case CHIP_TONGA:
1669b843c749SSergey Zigachev 	case CHIP_FIJI:
1670b843c749SSergey Zigachev 	case CHIP_CARRIZO:
1671b843c749SSergey Zigachev 	case CHIP_STONEY:
1672b843c749SSergey Zigachev 	case CHIP_POLARIS11:
1673b843c749SSergey Zigachev 	case CHIP_POLARIS10:
1674b843c749SSergey Zigachev 	case CHIP_POLARIS12:
1675b843c749SSergey Zigachev 	case CHIP_VEGAM:
1676b843c749SSergey Zigachev 	case CHIP_VEGA10:
1677b843c749SSergey Zigachev 	case CHIP_VEGA12:
1678b843c749SSergey Zigachev 	case CHIP_VEGA20:
1679b843c749SSergey Zigachev 		if (dce110_register_irq_handlers(dm->adev)) {
1680b843c749SSergey Zigachev 			DRM_ERROR("DM: Failed to initialize IRQ\n");
1681b843c749SSergey Zigachev 			goto fail;
1682b843c749SSergey Zigachev 		}
1683b843c749SSergey Zigachev 		break;
1684b843c749SSergey Zigachev #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
1685b843c749SSergey Zigachev 	case CHIP_RAVEN:
1686b843c749SSergey Zigachev 		if (dcn10_register_irq_handlers(dm->adev)) {
1687b843c749SSergey Zigachev 			DRM_ERROR("DM: Failed to initialize IRQ\n");
1688b843c749SSergey Zigachev 			goto fail;
1689b843c749SSergey Zigachev 		}
1690b843c749SSergey Zigachev 		break;
1691b843c749SSergey Zigachev #endif
1692b843c749SSergey Zigachev 	default:
1693b843c749SSergey Zigachev 		DRM_ERROR("Unsupported ASIC type: 0x%X\n", adev->asic_type);
1694b843c749SSergey Zigachev 		goto fail;
1695b843c749SSergey Zigachev 	}
1696b843c749SSergey Zigachev 
1697b843c749SSergey Zigachev 	if (adev->asic_type != CHIP_CARRIZO && adev->asic_type != CHIP_STONEY)
1698b843c749SSergey Zigachev 		dm->dc->debug.disable_stutter = amdgpu_pp_feature_mask & PP_STUTTER_MODE ? false : true;
1699b843c749SSergey Zigachev 
1700b843c749SSergey Zigachev 	return 0;
1701b843c749SSergey Zigachev fail:
1702b843c749SSergey Zigachev 	kfree(aencoder);
1703b843c749SSergey Zigachev 	kfree(aconnector);
1704b843c749SSergey Zigachev 	for (i = 0; i < dm->dc->caps.max_planes; i++)
1705b843c749SSergey Zigachev 		kfree(mode_info->planes[i]);
1706b843c749SSergey Zigachev 	return -1;
1707b843c749SSergey Zigachev }
1708b843c749SSergey Zigachev 
amdgpu_dm_destroy_drm_device(struct amdgpu_display_manager * dm)1709b843c749SSergey Zigachev static void amdgpu_dm_destroy_drm_device(struct amdgpu_display_manager *dm)
1710b843c749SSergey Zigachev {
1711b843c749SSergey Zigachev 	drm_mode_config_cleanup(dm->ddev);
1712b843c749SSergey Zigachev 	return;
1713b843c749SSergey Zigachev }
1714b843c749SSergey Zigachev 
1715b843c749SSergey Zigachev /******************************************************************************
1716b843c749SSergey Zigachev  * amdgpu_display_funcs functions
1717b843c749SSergey Zigachev  *****************************************************************************/
1718b843c749SSergey Zigachev 
1719b843c749SSergey Zigachev /**
1720b843c749SSergey Zigachev  * dm_bandwidth_update - program display watermarks
1721b843c749SSergey Zigachev  *
1722b843c749SSergey Zigachev  * @adev: amdgpu_device pointer
1723b843c749SSergey Zigachev  *
1724b843c749SSergey Zigachev  * Calculate and program the display watermarks and line buffer allocation.
1725b843c749SSergey Zigachev  */
dm_bandwidth_update(struct amdgpu_device * adev)1726b843c749SSergey Zigachev static void dm_bandwidth_update(struct amdgpu_device *adev)
1727b843c749SSergey Zigachev {
1728b843c749SSergey Zigachev 	/* TODO: implement later */
1729b843c749SSergey Zigachev }
1730b843c749SSergey Zigachev 
amdgpu_notify_freesync(struct drm_device * dev,void * data,struct drm_file * filp)1731b843c749SSergey Zigachev static int amdgpu_notify_freesync(struct drm_device *dev, void *data,
1732b843c749SSergey Zigachev 				struct drm_file *filp)
1733b843c749SSergey Zigachev {
1734b843c749SSergey Zigachev 	struct mod_freesync_params freesync_params;
1735b843c749SSergey Zigachev 	uint8_t num_streams;
1736b843c749SSergey Zigachev 	uint8_t i;
1737b843c749SSergey Zigachev 
1738b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev->dev_private;
1739b843c749SSergey Zigachev 	int r = 0;
1740b843c749SSergey Zigachev 
1741b843c749SSergey Zigachev 	/* Get freesync enable flag from DRM */
1742b843c749SSergey Zigachev 
1743b843c749SSergey Zigachev 	num_streams = dc_get_current_stream_count(adev->dm.dc);
1744b843c749SSergey Zigachev 
1745b843c749SSergey Zigachev 	for (i = 0; i < num_streams; i++) {
1746b843c749SSergey Zigachev 		struct dc_stream_state *stream;
1747b843c749SSergey Zigachev 		stream = dc_get_stream_at_index(adev->dm.dc, i);
1748b843c749SSergey Zigachev 
1749b843c749SSergey Zigachev 		mod_freesync_update_state(adev->dm.freesync_module,
1750b843c749SSergey Zigachev 					  &stream, 1, &freesync_params);
1751b843c749SSergey Zigachev 	}
1752b843c749SSergey Zigachev 
1753b843c749SSergey Zigachev 	return r;
1754b843c749SSergey Zigachev }
1755b843c749SSergey Zigachev 
1756b843c749SSergey Zigachev static const struct amdgpu_display_funcs dm_display_funcs = {
1757b843c749SSergey Zigachev 	.bandwidth_update = dm_bandwidth_update, /* called unconditionally */
1758b843c749SSergey Zigachev 	.vblank_get_counter = dm_vblank_get_counter,/* called unconditionally */
1759b843c749SSergey Zigachev 	.backlight_set_level = NULL, /* never called for DC */
1760b843c749SSergey Zigachev 	.backlight_get_level = NULL, /* never called for DC */
1761b843c749SSergey Zigachev 	.hpd_sense = NULL,/* called unconditionally */
1762b843c749SSergey Zigachev 	.hpd_set_polarity = NULL, /* called unconditionally */
1763b843c749SSergey Zigachev 	.hpd_get_gpio_reg = NULL, /* VBIOS parsing. DAL does it. */
1764b843c749SSergey Zigachev 	.page_flip_get_scanoutpos =
1765b843c749SSergey Zigachev 		dm_crtc_get_scanoutpos,/* called unconditionally */
1766b843c749SSergey Zigachev 	.add_encoder = NULL, /* VBIOS parsing. DAL does it. */
1767b843c749SSergey Zigachev 	.add_connector = NULL, /* VBIOS parsing. DAL does it. */
1768b843c749SSergey Zigachev 	.notify_freesync = amdgpu_notify_freesync,
1769b843c749SSergey Zigachev 
1770b843c749SSergey Zigachev };
1771b843c749SSergey Zigachev 
1772b843c749SSergey Zigachev #if defined(CONFIG_DEBUG_KERNEL_DC)
1773b843c749SSergey Zigachev 
s3_debug_store(struct device * device,struct device_attribute * attr,const char * buf,size_t count)1774b843c749SSergey Zigachev static ssize_t s3_debug_store(struct device *device,
1775b843c749SSergey Zigachev 			      struct device_attribute *attr,
1776b843c749SSergey Zigachev 			      const char *buf,
1777b843c749SSergey Zigachev 			      size_t count)
1778b843c749SSergey Zigachev {
1779b843c749SSergey Zigachev 	int ret;
1780b843c749SSergey Zigachev 	int s3_state;
1781b843c749SSergey Zigachev 	struct pci_dev *pdev = to_pci_dev(device);
1782b843c749SSergey Zigachev 	struct drm_device *drm_dev = pci_get_drvdata(pdev);
1783b843c749SSergey Zigachev 	struct amdgpu_device *adev = drm_dev->dev_private;
1784b843c749SSergey Zigachev 
1785b843c749SSergey Zigachev 	ret = kstrtoint(buf, 0, &s3_state);
1786b843c749SSergey Zigachev 
1787b843c749SSergey Zigachev 	if (ret == 0) {
1788b843c749SSergey Zigachev 		if (s3_state) {
1789b843c749SSergey Zigachev 			dm_resume(adev);
1790b843c749SSergey Zigachev 			drm_kms_helper_hotplug_event(adev->ddev);
1791b843c749SSergey Zigachev 		} else
1792b843c749SSergey Zigachev 			dm_suspend(adev);
1793b843c749SSergey Zigachev 	}
1794b843c749SSergey Zigachev 
1795b843c749SSergey Zigachev 	return ret == 0 ? count : 0;
1796b843c749SSergey Zigachev }
1797b843c749SSergey Zigachev 
1798b843c749SSergey Zigachev DEVICE_ATTR_WO(s3_debug);
1799b843c749SSergey Zigachev 
1800b843c749SSergey Zigachev #endif
1801b843c749SSergey Zigachev 
dm_early_init(void * handle)1802b843c749SSergey Zigachev static int dm_early_init(void *handle)
1803b843c749SSergey Zigachev {
1804b843c749SSergey Zigachev 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
1805b843c749SSergey Zigachev 
1806b843c749SSergey Zigachev 	switch (adev->asic_type) {
1807b843c749SSergey Zigachev 	case CHIP_BONAIRE:
1808b843c749SSergey Zigachev 	case CHIP_HAWAII:
1809b843c749SSergey Zigachev 		adev->mode_info.num_crtc = 6;
1810b843c749SSergey Zigachev 		adev->mode_info.num_hpd = 6;
1811b843c749SSergey Zigachev 		adev->mode_info.num_dig = 6;
1812b843c749SSergey Zigachev 		adev->mode_info.plane_type = dm_plane_type_default;
1813b843c749SSergey Zigachev 		break;
1814b843c749SSergey Zigachev 	case CHIP_KAVERI:
1815b843c749SSergey Zigachev 		adev->mode_info.num_crtc = 4;
1816b843c749SSergey Zigachev 		adev->mode_info.num_hpd = 6;
1817b843c749SSergey Zigachev 		adev->mode_info.num_dig = 7;
1818b843c749SSergey Zigachev 		adev->mode_info.plane_type = dm_plane_type_default;
1819b843c749SSergey Zigachev 		break;
1820b843c749SSergey Zigachev 	case CHIP_KABINI:
1821b843c749SSergey Zigachev 	case CHIP_MULLINS:
1822b843c749SSergey Zigachev 		adev->mode_info.num_crtc = 2;
1823b843c749SSergey Zigachev 		adev->mode_info.num_hpd = 6;
1824b843c749SSergey Zigachev 		adev->mode_info.num_dig = 6;
1825b843c749SSergey Zigachev 		adev->mode_info.plane_type = dm_plane_type_default;
1826b843c749SSergey Zigachev 		break;
1827b843c749SSergey Zigachev 	case CHIP_FIJI:
1828b843c749SSergey Zigachev 	case CHIP_TONGA:
1829b843c749SSergey Zigachev 		adev->mode_info.num_crtc = 6;
1830b843c749SSergey Zigachev 		adev->mode_info.num_hpd = 6;
1831b843c749SSergey Zigachev 		adev->mode_info.num_dig = 7;
1832b843c749SSergey Zigachev 		adev->mode_info.plane_type = dm_plane_type_default;
1833b843c749SSergey Zigachev 		break;
1834b843c749SSergey Zigachev 	case CHIP_CARRIZO:
1835b843c749SSergey Zigachev 		adev->mode_info.num_crtc = 3;
1836b843c749SSergey Zigachev 		adev->mode_info.num_hpd = 6;
1837b843c749SSergey Zigachev 		adev->mode_info.num_dig = 9;
1838b843c749SSergey Zigachev 		adev->mode_info.plane_type = dm_plane_type_carizzo;
1839b843c749SSergey Zigachev 		break;
1840b843c749SSergey Zigachev 	case CHIP_STONEY:
1841b843c749SSergey Zigachev 		adev->mode_info.num_crtc = 2;
1842b843c749SSergey Zigachev 		adev->mode_info.num_hpd = 6;
1843b843c749SSergey Zigachev 		adev->mode_info.num_dig = 9;
1844b843c749SSergey Zigachev 		adev->mode_info.plane_type = dm_plane_type_stoney;
1845b843c749SSergey Zigachev 		break;
1846b843c749SSergey Zigachev 	case CHIP_POLARIS11:
1847b843c749SSergey Zigachev 	case CHIP_POLARIS12:
1848b843c749SSergey Zigachev 		adev->mode_info.num_crtc = 5;
1849b843c749SSergey Zigachev 		adev->mode_info.num_hpd = 5;
1850b843c749SSergey Zigachev 		adev->mode_info.num_dig = 5;
1851b843c749SSergey Zigachev 		adev->mode_info.plane_type = dm_plane_type_default;
1852b843c749SSergey Zigachev 		break;
1853b843c749SSergey Zigachev 	case CHIP_POLARIS10:
1854b843c749SSergey Zigachev 	case CHIP_VEGAM:
1855b843c749SSergey Zigachev 		adev->mode_info.num_crtc = 6;
1856b843c749SSergey Zigachev 		adev->mode_info.num_hpd = 6;
1857b843c749SSergey Zigachev 		adev->mode_info.num_dig = 6;
1858b843c749SSergey Zigachev 		adev->mode_info.plane_type = dm_plane_type_default;
1859b843c749SSergey Zigachev 		break;
1860b843c749SSergey Zigachev 	case CHIP_VEGA10:
1861b843c749SSergey Zigachev 	case CHIP_VEGA12:
1862b843c749SSergey Zigachev 	case CHIP_VEGA20:
1863b843c749SSergey Zigachev 		adev->mode_info.num_crtc = 6;
1864b843c749SSergey Zigachev 		adev->mode_info.num_hpd = 6;
1865b843c749SSergey Zigachev 		adev->mode_info.num_dig = 6;
1866b843c749SSergey Zigachev 		adev->mode_info.plane_type = dm_plane_type_default;
1867b843c749SSergey Zigachev 		break;
1868b843c749SSergey Zigachev #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
1869b843c749SSergey Zigachev 	case CHIP_RAVEN:
1870b843c749SSergey Zigachev 		adev->mode_info.num_crtc = 4;
1871b843c749SSergey Zigachev 		adev->mode_info.num_hpd = 4;
1872b843c749SSergey Zigachev 		adev->mode_info.num_dig = 4;
1873b843c749SSergey Zigachev 		adev->mode_info.plane_type = dm_plane_type_default;
1874b843c749SSergey Zigachev 		break;
1875b843c749SSergey Zigachev #endif
1876b843c749SSergey Zigachev 	default:
1877b843c749SSergey Zigachev 		DRM_ERROR("Unsupported ASIC type: 0x%X\n", adev->asic_type);
1878b843c749SSergey Zigachev 		return -EINVAL;
1879b843c749SSergey Zigachev 	}
1880b843c749SSergey Zigachev 
1881b843c749SSergey Zigachev 	amdgpu_dm_set_irq_funcs(adev);
1882b843c749SSergey Zigachev 
1883b843c749SSergey Zigachev 	if (adev->mode_info.funcs == NULL)
1884b843c749SSergey Zigachev 		adev->mode_info.funcs = &dm_display_funcs;
1885b843c749SSergey Zigachev 
1886b843c749SSergey Zigachev 	/* Note: Do NOT change adev->audio_endpt_rreg and
1887b843c749SSergey Zigachev 	 * adev->audio_endpt_wreg because they are initialised in
1888b843c749SSergey Zigachev 	 * amdgpu_device_init() */
1889b843c749SSergey Zigachev #if defined(CONFIG_DEBUG_KERNEL_DC)
1890b843c749SSergey Zigachev 	device_create_file(
1891b843c749SSergey Zigachev 		adev->ddev->dev,
1892b843c749SSergey Zigachev 		&dev_attr_s3_debug);
1893b843c749SSergey Zigachev #endif
1894b843c749SSergey Zigachev 
1895b843c749SSergey Zigachev 	return 0;
1896b843c749SSergey Zigachev }
1897b843c749SSergey Zigachev 
modeset_required(struct drm_crtc_state * crtc_state,struct dc_stream_state * new_stream,struct dc_stream_state * old_stream)1898b843c749SSergey Zigachev static bool modeset_required(struct drm_crtc_state *crtc_state,
1899b843c749SSergey Zigachev 			     struct dc_stream_state *new_stream,
1900b843c749SSergey Zigachev 			     struct dc_stream_state *old_stream)
1901b843c749SSergey Zigachev {
1902b843c749SSergey Zigachev 	if (!drm_atomic_crtc_needs_modeset(crtc_state))
1903b843c749SSergey Zigachev 		return false;
1904b843c749SSergey Zigachev 
1905b843c749SSergey Zigachev 	if (!crtc_state->enable)
1906b843c749SSergey Zigachev 		return false;
1907b843c749SSergey Zigachev 
1908b843c749SSergey Zigachev 	return crtc_state->active;
1909b843c749SSergey Zigachev }
1910b843c749SSergey Zigachev 
modereset_required(struct drm_crtc_state * crtc_state)1911b843c749SSergey Zigachev static bool modereset_required(struct drm_crtc_state *crtc_state)
1912b843c749SSergey Zigachev {
1913b843c749SSergey Zigachev 	if (!drm_atomic_crtc_needs_modeset(crtc_state))
1914b843c749SSergey Zigachev 		return false;
1915b843c749SSergey Zigachev 
1916b843c749SSergey Zigachev 	return !crtc_state->enable || !crtc_state->active;
1917b843c749SSergey Zigachev }
1918b843c749SSergey Zigachev 
amdgpu_dm_encoder_destroy(struct drm_encoder * encoder)1919b843c749SSergey Zigachev static void amdgpu_dm_encoder_destroy(struct drm_encoder *encoder)
1920b843c749SSergey Zigachev {
1921b843c749SSergey Zigachev 	drm_encoder_cleanup(encoder);
1922b843c749SSergey Zigachev 	kfree(encoder);
1923b843c749SSergey Zigachev }
1924b843c749SSergey Zigachev 
1925b843c749SSergey Zigachev static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs = {
1926b843c749SSergey Zigachev 	.destroy = amdgpu_dm_encoder_destroy,
1927b843c749SSergey Zigachev };
1928b843c749SSergey Zigachev 
fill_rects_from_plane_state(const struct drm_plane_state * state,struct dc_plane_state * plane_state)1929b843c749SSergey Zigachev static bool fill_rects_from_plane_state(const struct drm_plane_state *state,
1930b843c749SSergey Zigachev 					struct dc_plane_state *plane_state)
1931b843c749SSergey Zigachev {
1932b843c749SSergey Zigachev 	plane_state->src_rect.x = state->src_x >> 16;
1933b843c749SSergey Zigachev 	plane_state->src_rect.y = state->src_y >> 16;
1934b843c749SSergey Zigachev 	/*we ignore for now mantissa and do not to deal with floating pixels :(*/
1935b843c749SSergey Zigachev 	plane_state->src_rect.width = state->src_w >> 16;
1936b843c749SSergey Zigachev 
1937b843c749SSergey Zigachev 	if (plane_state->src_rect.width == 0)
1938b843c749SSergey Zigachev 		return false;
1939b843c749SSergey Zigachev 
1940b843c749SSergey Zigachev 	plane_state->src_rect.height = state->src_h >> 16;
1941b843c749SSergey Zigachev 	if (plane_state->src_rect.height == 0)
1942b843c749SSergey Zigachev 		return false;
1943b843c749SSergey Zigachev 
1944b843c749SSergey Zigachev 	plane_state->dst_rect.x = state->crtc_x;
1945b843c749SSergey Zigachev 	plane_state->dst_rect.y = state->crtc_y;
1946b843c749SSergey Zigachev 
1947b843c749SSergey Zigachev 	if (state->crtc_w == 0)
1948b843c749SSergey Zigachev 		return false;
1949b843c749SSergey Zigachev 
1950b843c749SSergey Zigachev 	plane_state->dst_rect.width = state->crtc_w;
1951b843c749SSergey Zigachev 
1952b843c749SSergey Zigachev 	if (state->crtc_h == 0)
1953b843c749SSergey Zigachev 		return false;
1954b843c749SSergey Zigachev 
1955b843c749SSergey Zigachev 	plane_state->dst_rect.height = state->crtc_h;
1956b843c749SSergey Zigachev 
1957b843c749SSergey Zigachev 	plane_state->clip_rect = plane_state->dst_rect;
1958b843c749SSergey Zigachev 
1959b843c749SSergey Zigachev 	switch (state->rotation & DRM_MODE_ROTATE_MASK) {
1960b843c749SSergey Zigachev 	case DRM_MODE_ROTATE_0:
1961b843c749SSergey Zigachev 		plane_state->rotation = ROTATION_ANGLE_0;
1962b843c749SSergey Zigachev 		break;
1963b843c749SSergey Zigachev 	case DRM_MODE_ROTATE_90:
1964b843c749SSergey Zigachev 		plane_state->rotation = ROTATION_ANGLE_90;
1965b843c749SSergey Zigachev 		break;
1966b843c749SSergey Zigachev 	case DRM_MODE_ROTATE_180:
1967b843c749SSergey Zigachev 		plane_state->rotation = ROTATION_ANGLE_180;
1968b843c749SSergey Zigachev 		break;
1969b843c749SSergey Zigachev 	case DRM_MODE_ROTATE_270:
1970b843c749SSergey Zigachev 		plane_state->rotation = ROTATION_ANGLE_270;
1971b843c749SSergey Zigachev 		break;
1972b843c749SSergey Zigachev 	default:
1973b843c749SSergey Zigachev 		plane_state->rotation = ROTATION_ANGLE_0;
1974b843c749SSergey Zigachev 		break;
1975b843c749SSergey Zigachev 	}
1976b843c749SSergey Zigachev 
1977b843c749SSergey Zigachev 	return true;
1978b843c749SSergey Zigachev }
get_fb_info(const struct amdgpu_framebuffer * amdgpu_fb,uint64_t * tiling_flags)1979b843c749SSergey Zigachev static int get_fb_info(const struct amdgpu_framebuffer *amdgpu_fb,
1980b843c749SSergey Zigachev 		       uint64_t *tiling_flags)
1981b843c749SSergey Zigachev {
1982b843c749SSergey Zigachev 	struct amdgpu_bo *rbo = gem_to_amdgpu_bo(amdgpu_fb->base.obj[0]);
1983b843c749SSergey Zigachev 	int r = amdgpu_bo_reserve(rbo, false);
1984b843c749SSergey Zigachev 
1985b843c749SSergey Zigachev 	if (unlikely(r)) {
1986b843c749SSergey Zigachev 		// Don't show error msg. when return -ERESTARTSYS
1987b843c749SSergey Zigachev 		if (r != -ERESTARTSYS)
1988b843c749SSergey Zigachev 			DRM_ERROR("Unable to reserve buffer: %d\n", r);
1989b843c749SSergey Zigachev 		return r;
1990b843c749SSergey Zigachev 	}
1991b843c749SSergey Zigachev 
1992b843c749SSergey Zigachev 	if (tiling_flags)
1993*78973132SSergey Zigachev 		amdgpu_bo_get_tiling_flags(rbo, (u64 *)tiling_flags);
1994b843c749SSergey Zigachev 
1995b843c749SSergey Zigachev 	amdgpu_bo_unreserve(rbo);
1996b843c749SSergey Zigachev 
1997b843c749SSergey Zigachev 	return r;
1998b843c749SSergey Zigachev }
1999b843c749SSergey Zigachev 
fill_plane_attributes_from_fb(struct amdgpu_device * adev,struct dc_plane_state * plane_state,const struct amdgpu_framebuffer * amdgpu_fb)2000b843c749SSergey Zigachev static int fill_plane_attributes_from_fb(struct amdgpu_device *adev,
2001b843c749SSergey Zigachev 					 struct dc_plane_state *plane_state,
2002b843c749SSergey Zigachev 					 const struct amdgpu_framebuffer *amdgpu_fb)
2003b843c749SSergey Zigachev {
2004b843c749SSergey Zigachev 	uint64_t tiling_flags;
2005b843c749SSergey Zigachev 	unsigned int awidth;
2006b843c749SSergey Zigachev 	const struct drm_framebuffer *fb = &amdgpu_fb->base;
2007b843c749SSergey Zigachev 	int ret = 0;
2008b843c749SSergey Zigachev 	struct drm_format_name_buf format_name;
2009b843c749SSergey Zigachev 
2010b843c749SSergey Zigachev 	ret = get_fb_info(
2011b843c749SSergey Zigachev 		amdgpu_fb,
2012b843c749SSergey Zigachev 		&tiling_flags);
2013b843c749SSergey Zigachev 
2014b843c749SSergey Zigachev 	if (ret)
2015b843c749SSergey Zigachev 		return ret;
2016b843c749SSergey Zigachev 
2017b843c749SSergey Zigachev 	switch (fb->format->format) {
2018b843c749SSergey Zigachev 	case DRM_FORMAT_C8:
2019b843c749SSergey Zigachev 		plane_state->format = SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS;
2020b843c749SSergey Zigachev 		break;
2021b843c749SSergey Zigachev 	case DRM_FORMAT_RGB565:
2022b843c749SSergey Zigachev 		plane_state->format = SURFACE_PIXEL_FORMAT_GRPH_RGB565;
2023b843c749SSergey Zigachev 		break;
2024b843c749SSergey Zigachev 	case DRM_FORMAT_XRGB8888:
2025b843c749SSergey Zigachev 	case DRM_FORMAT_ARGB8888:
2026b843c749SSergey Zigachev 		plane_state->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB8888;
2027b843c749SSergey Zigachev 		break;
2028b843c749SSergey Zigachev 	case DRM_FORMAT_XRGB2101010:
2029b843c749SSergey Zigachev 	case DRM_FORMAT_ARGB2101010:
2030b843c749SSergey Zigachev 		plane_state->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010;
2031b843c749SSergey Zigachev 		break;
2032b843c749SSergey Zigachev 	case DRM_FORMAT_XBGR2101010:
2033b843c749SSergey Zigachev 	case DRM_FORMAT_ABGR2101010:
2034b843c749SSergey Zigachev 		plane_state->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010;
2035b843c749SSergey Zigachev 		break;
2036b843c749SSergey Zigachev 	case DRM_FORMAT_NV21:
2037b843c749SSergey Zigachev 		plane_state->format = SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr;
2038b843c749SSergey Zigachev 		break;
2039b843c749SSergey Zigachev 	case DRM_FORMAT_NV12:
2040b843c749SSergey Zigachev 		plane_state->format = SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb;
2041b843c749SSergey Zigachev 		break;
2042b843c749SSergey Zigachev 	default:
2043b843c749SSergey Zigachev 		DRM_ERROR("Unsupported screen format %s\n",
2044b843c749SSergey Zigachev 			  drm_get_format_name(fb->format->format, &format_name));
2045b843c749SSergey Zigachev 		return -EINVAL;
2046b843c749SSergey Zigachev 	}
2047b843c749SSergey Zigachev 
2048b843c749SSergey Zigachev 	if (plane_state->format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) {
2049b843c749SSergey Zigachev 		plane_state->address.type = PLN_ADDR_TYPE_GRAPHICS;
2050b843c749SSergey Zigachev 		plane_state->plane_size.grph.surface_size.x = 0;
2051b843c749SSergey Zigachev 		plane_state->plane_size.grph.surface_size.y = 0;
2052b843c749SSergey Zigachev 		plane_state->plane_size.grph.surface_size.width = fb->width;
2053b843c749SSergey Zigachev 		plane_state->plane_size.grph.surface_size.height = fb->height;
2054b843c749SSergey Zigachev 		plane_state->plane_size.grph.surface_pitch =
2055b843c749SSergey Zigachev 				fb->pitches[0] / fb->format->cpp[0];
2056b843c749SSergey Zigachev 		/* TODO: unhardcode */
2057b843c749SSergey Zigachev 		plane_state->color_space = COLOR_SPACE_SRGB;
2058b843c749SSergey Zigachev 
2059b843c749SSergey Zigachev 	} else {
2060b843c749SSergey Zigachev 		awidth = ALIGN(fb->width, 64);
2061b843c749SSergey Zigachev 		plane_state->address.type = PLN_ADDR_TYPE_VIDEO_PROGRESSIVE;
2062b843c749SSergey Zigachev 		plane_state->plane_size.video.luma_size.x = 0;
2063b843c749SSergey Zigachev 		plane_state->plane_size.video.luma_size.y = 0;
2064b843c749SSergey Zigachev 		plane_state->plane_size.video.luma_size.width = awidth;
2065b843c749SSergey Zigachev 		plane_state->plane_size.video.luma_size.height = fb->height;
2066b843c749SSergey Zigachev 		/* TODO: unhardcode */
2067b843c749SSergey Zigachev 		plane_state->plane_size.video.luma_pitch = awidth;
2068b843c749SSergey Zigachev 
2069b843c749SSergey Zigachev 		plane_state->plane_size.video.chroma_size.x = 0;
2070b843c749SSergey Zigachev 		plane_state->plane_size.video.chroma_size.y = 0;
2071b843c749SSergey Zigachev 		plane_state->plane_size.video.chroma_size.width = awidth;
2072b843c749SSergey Zigachev 		plane_state->plane_size.video.chroma_size.height = fb->height;
2073b843c749SSergey Zigachev 		plane_state->plane_size.video.chroma_pitch = awidth / 2;
2074b843c749SSergey Zigachev 
2075b843c749SSergey Zigachev 		/* TODO: unhardcode */
2076b843c749SSergey Zigachev 		plane_state->color_space = COLOR_SPACE_YCBCR709;
2077b843c749SSergey Zigachev 	}
2078b843c749SSergey Zigachev 
2079b843c749SSergey Zigachev 	memset(&plane_state->tiling_info, 0, sizeof(plane_state->tiling_info));
2080b843c749SSergey Zigachev 
2081b843c749SSergey Zigachev 	/* Fill GFX8 params */
2082b843c749SSergey Zigachev 	if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) == DC_ARRAY_2D_TILED_THIN1) {
2083b843c749SSergey Zigachev 		unsigned int bankw, bankh, mtaspect, tile_split, num_banks;
2084b843c749SSergey Zigachev 
2085b843c749SSergey Zigachev 		bankw = AMDGPU_TILING_GET(tiling_flags, BANK_WIDTH);
2086b843c749SSergey Zigachev 		bankh = AMDGPU_TILING_GET(tiling_flags, BANK_HEIGHT);
2087b843c749SSergey Zigachev 		mtaspect = AMDGPU_TILING_GET(tiling_flags, MACRO_TILE_ASPECT);
2088b843c749SSergey Zigachev 		tile_split = AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT);
2089b843c749SSergey Zigachev 		num_banks = AMDGPU_TILING_GET(tiling_flags, NUM_BANKS);
2090b843c749SSergey Zigachev 
2091b843c749SSergey Zigachev 		/* XXX fix me for VI */
2092b843c749SSergey Zigachev 		plane_state->tiling_info.gfx8.num_banks = num_banks;
2093b843c749SSergey Zigachev 		plane_state->tiling_info.gfx8.array_mode =
2094b843c749SSergey Zigachev 				DC_ARRAY_2D_TILED_THIN1;
2095b843c749SSergey Zigachev 		plane_state->tiling_info.gfx8.tile_split = tile_split;
2096b843c749SSergey Zigachev 		plane_state->tiling_info.gfx8.bank_width = bankw;
2097b843c749SSergey Zigachev 		plane_state->tiling_info.gfx8.bank_height = bankh;
2098b843c749SSergey Zigachev 		plane_state->tiling_info.gfx8.tile_aspect = mtaspect;
2099b843c749SSergey Zigachev 		plane_state->tiling_info.gfx8.tile_mode =
2100b843c749SSergey Zigachev 				DC_ADDR_SURF_MICRO_TILING_DISPLAY;
2101b843c749SSergey Zigachev 	} else if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE)
2102b843c749SSergey Zigachev 			== DC_ARRAY_1D_TILED_THIN1) {
2103b843c749SSergey Zigachev 		plane_state->tiling_info.gfx8.array_mode = DC_ARRAY_1D_TILED_THIN1;
2104b843c749SSergey Zigachev 	}
2105b843c749SSergey Zigachev 
2106b843c749SSergey Zigachev 	plane_state->tiling_info.gfx8.pipe_config =
2107b843c749SSergey Zigachev 			AMDGPU_TILING_GET(tiling_flags, PIPE_CONFIG);
2108b843c749SSergey Zigachev 
2109b843c749SSergey Zigachev 	if (adev->asic_type == CHIP_VEGA10 ||
2110b843c749SSergey Zigachev 	    adev->asic_type == CHIP_VEGA12 ||
2111b843c749SSergey Zigachev 	    adev->asic_type == CHIP_VEGA20 ||
2112b843c749SSergey Zigachev 	    adev->asic_type == CHIP_RAVEN) {
2113b843c749SSergey Zigachev 		/* Fill GFX9 params */
2114b843c749SSergey Zigachev 		plane_state->tiling_info.gfx9.num_pipes =
2115b843c749SSergey Zigachev 			adev->gfx.config.gb_addr_config_fields.num_pipes;
2116b843c749SSergey Zigachev 		plane_state->tiling_info.gfx9.num_banks =
2117b843c749SSergey Zigachev 			adev->gfx.config.gb_addr_config_fields.num_banks;
2118b843c749SSergey Zigachev 		plane_state->tiling_info.gfx9.pipe_interleave =
2119b843c749SSergey Zigachev 			adev->gfx.config.gb_addr_config_fields.pipe_interleave_size;
2120b843c749SSergey Zigachev 		plane_state->tiling_info.gfx9.num_shader_engines =
2121b843c749SSergey Zigachev 			adev->gfx.config.gb_addr_config_fields.num_se;
2122b843c749SSergey Zigachev 		plane_state->tiling_info.gfx9.max_compressed_frags =
2123b843c749SSergey Zigachev 			adev->gfx.config.gb_addr_config_fields.max_compress_frags;
2124b843c749SSergey Zigachev 		plane_state->tiling_info.gfx9.num_rb_per_se =
2125b843c749SSergey Zigachev 			adev->gfx.config.gb_addr_config_fields.num_rb_per_se;
2126b843c749SSergey Zigachev 		plane_state->tiling_info.gfx9.swizzle =
2127b843c749SSergey Zigachev 			AMDGPU_TILING_GET(tiling_flags, SWIZZLE_MODE);
2128b843c749SSergey Zigachev 		plane_state->tiling_info.gfx9.shaderEnable = 1;
2129b843c749SSergey Zigachev 	}
2130b843c749SSergey Zigachev 
2131b843c749SSergey Zigachev 	plane_state->visible = true;
2132b843c749SSergey Zigachev 	plane_state->scaling_quality.h_taps_c = 0;
2133b843c749SSergey Zigachev 	plane_state->scaling_quality.v_taps_c = 0;
2134b843c749SSergey Zigachev 
2135b843c749SSergey Zigachev 	/* is this needed? is plane_state zeroed at allocation? */
2136b843c749SSergey Zigachev 	plane_state->scaling_quality.h_taps = 0;
2137b843c749SSergey Zigachev 	plane_state->scaling_quality.v_taps = 0;
2138b843c749SSergey Zigachev 	plane_state->stereo_format = PLANE_STEREO_FORMAT_NONE;
2139b843c749SSergey Zigachev 
2140b843c749SSergey Zigachev 	return ret;
2141b843c749SSergey Zigachev 
2142b843c749SSergey Zigachev }
2143b843c749SSergey Zigachev 
fill_plane_attributes(struct amdgpu_device * adev,struct dc_plane_state * dc_plane_state,struct drm_plane_state * plane_state,struct drm_crtc_state * crtc_state)2144b843c749SSergey Zigachev static int fill_plane_attributes(struct amdgpu_device *adev,
2145b843c749SSergey Zigachev 				 struct dc_plane_state *dc_plane_state,
2146b843c749SSergey Zigachev 				 struct drm_plane_state *plane_state,
2147b843c749SSergey Zigachev 				 struct drm_crtc_state *crtc_state)
2148b843c749SSergey Zigachev {
2149b843c749SSergey Zigachev 	const struct amdgpu_framebuffer *amdgpu_fb =
2150b843c749SSergey Zigachev 		to_amdgpu_framebuffer(plane_state->fb);
2151b843c749SSergey Zigachev 	const struct drm_crtc *crtc = plane_state->crtc;
2152b843c749SSergey Zigachev 	int ret = 0;
2153b843c749SSergey Zigachev 
2154b843c749SSergey Zigachev 	if (!fill_rects_from_plane_state(plane_state, dc_plane_state))
2155b843c749SSergey Zigachev 		return -EINVAL;
2156b843c749SSergey Zigachev 
2157b843c749SSergey Zigachev 	ret = fill_plane_attributes_from_fb(
2158b843c749SSergey Zigachev 		crtc->dev->dev_private,
2159b843c749SSergey Zigachev 		dc_plane_state,
2160b843c749SSergey Zigachev 		amdgpu_fb);
2161b843c749SSergey Zigachev 
2162b843c749SSergey Zigachev 	if (ret)
2163b843c749SSergey Zigachev 		return ret;
2164b843c749SSergey Zigachev 
2165b843c749SSergey Zigachev 	/*
2166b843c749SSergey Zigachev 	 * Always set input transfer function, since plane state is refreshed
2167b843c749SSergey Zigachev 	 * every time.
2168b843c749SSergey Zigachev 	 */
2169b843c749SSergey Zigachev 	ret = amdgpu_dm_set_degamma_lut(crtc_state, dc_plane_state);
2170b843c749SSergey Zigachev 	if (ret) {
2171b843c749SSergey Zigachev 		dc_transfer_func_release(dc_plane_state->in_transfer_func);
2172b843c749SSergey Zigachev 		dc_plane_state->in_transfer_func = NULL;
2173b843c749SSergey Zigachev 	}
2174b843c749SSergey Zigachev 
2175b843c749SSergey Zigachev 	return ret;
2176b843c749SSergey Zigachev }
2177b843c749SSergey Zigachev 
2178b843c749SSergey Zigachev /*****************************************************************************/
2179b843c749SSergey Zigachev 
update_stream_scaling_settings(const struct drm_display_mode * mode,const struct dm_connector_state * dm_state,struct dc_stream_state * stream)2180b843c749SSergey Zigachev static void update_stream_scaling_settings(const struct drm_display_mode *mode,
2181b843c749SSergey Zigachev 					   const struct dm_connector_state *dm_state,
2182b843c749SSergey Zigachev 					   struct dc_stream_state *stream)
2183b843c749SSergey Zigachev {
2184b843c749SSergey Zigachev 	enum amdgpu_rmx_type rmx_type;
2185b843c749SSergey Zigachev 
2186b843c749SSergey Zigachev 	struct rect src = { 0 }; /* viewport in composition space*/
2187b843c749SSergey Zigachev 	struct rect dst = { 0 }; /* stream addressable area */
2188b843c749SSergey Zigachev 
2189b843c749SSergey Zigachev 	/* no mode. nothing to be done */
2190b843c749SSergey Zigachev 	if (!mode)
2191b843c749SSergey Zigachev 		return;
2192b843c749SSergey Zigachev 
2193b843c749SSergey Zigachev 	/* Full screen scaling by default */
2194b843c749SSergey Zigachev 	src.width = mode->hdisplay;
2195b843c749SSergey Zigachev 	src.height = mode->vdisplay;
2196b843c749SSergey Zigachev 	dst.width = stream->timing.h_addressable;
2197b843c749SSergey Zigachev 	dst.height = stream->timing.v_addressable;
2198b843c749SSergey Zigachev 
2199b843c749SSergey Zigachev 	if (dm_state) {
2200b843c749SSergey Zigachev 		rmx_type = dm_state->scaling;
2201b843c749SSergey Zigachev 		if (rmx_type == RMX_ASPECT || rmx_type == RMX_OFF) {
2202b843c749SSergey Zigachev 			if (src.width * dst.height <
2203b843c749SSergey Zigachev 					src.height * dst.width) {
2204b843c749SSergey Zigachev 				/* height needs less upscaling/more downscaling */
2205b843c749SSergey Zigachev 				dst.width = src.width *
2206b843c749SSergey Zigachev 						dst.height / src.height;
2207b843c749SSergey Zigachev 			} else {
2208b843c749SSergey Zigachev 				/* width needs less upscaling/more downscaling */
2209b843c749SSergey Zigachev 				dst.height = src.height *
2210b843c749SSergey Zigachev 						dst.width / src.width;
2211b843c749SSergey Zigachev 			}
2212b843c749SSergey Zigachev 		} else if (rmx_type == RMX_CENTER) {
2213b843c749SSergey Zigachev 			dst = src;
2214b843c749SSergey Zigachev 		}
2215b843c749SSergey Zigachev 
2216b843c749SSergey Zigachev 		dst.x = (stream->timing.h_addressable - dst.width) / 2;
2217b843c749SSergey Zigachev 		dst.y = (stream->timing.v_addressable - dst.height) / 2;
2218b843c749SSergey Zigachev 
2219b843c749SSergey Zigachev 		if (dm_state->underscan_enable) {
2220b843c749SSergey Zigachev 			dst.x += dm_state->underscan_hborder / 2;
2221b843c749SSergey Zigachev 			dst.y += dm_state->underscan_vborder / 2;
2222b843c749SSergey Zigachev 			dst.width -= dm_state->underscan_hborder;
2223b843c749SSergey Zigachev 			dst.height -= dm_state->underscan_vborder;
2224b843c749SSergey Zigachev 		}
2225b843c749SSergey Zigachev 	}
2226b843c749SSergey Zigachev 
2227b843c749SSergey Zigachev 	stream->src = src;
2228b843c749SSergey Zigachev 	stream->dst = dst;
2229b843c749SSergey Zigachev 
2230b843c749SSergey Zigachev 	DRM_DEBUG_DRIVER("Destination Rectangle x:%d  y:%d  width:%d  height:%d\n",
2231b843c749SSergey Zigachev 			dst.x, dst.y, dst.width, dst.height);
2232b843c749SSergey Zigachev 
2233b843c749SSergey Zigachev }
2234b843c749SSergey Zigachev 
2235b843c749SSergey Zigachev static enum dc_color_depth
convert_color_depth_from_display_info(const struct drm_connector * connector)2236b843c749SSergey Zigachev convert_color_depth_from_display_info(const struct drm_connector *connector)
2237b843c749SSergey Zigachev {
2238b843c749SSergey Zigachev 	struct dm_connector_state *dm_conn_state =
2239b843c749SSergey Zigachev 		to_dm_connector_state(connector->state);
2240b843c749SSergey Zigachev 	uint32_t bpc = connector->display_info.bpc;
2241b843c749SSergey Zigachev 
2242b843c749SSergey Zigachev 	/* TODO: Remove this when there's support for max_bpc in drm */
2243b843c749SSergey Zigachev 	if (dm_conn_state && bpc > dm_conn_state->max_bpc)
2244b843c749SSergey Zigachev 		/* Round down to nearest even number. */
2245b843c749SSergey Zigachev 		bpc = dm_conn_state->max_bpc - (dm_conn_state->max_bpc & 1);
2246b843c749SSergey Zigachev 
2247b843c749SSergey Zigachev 	switch (bpc) {
2248b843c749SSergey Zigachev 	case 0:
2249b843c749SSergey Zigachev 		/* Temporary Work around, DRM don't parse color depth for
2250b843c749SSergey Zigachev 		 * EDID revision before 1.4
2251b843c749SSergey Zigachev 		 * TODO: Fix edid parsing
2252b843c749SSergey Zigachev 		 */
2253b843c749SSergey Zigachev 		return COLOR_DEPTH_888;
2254b843c749SSergey Zigachev 	case 6:
2255b843c749SSergey Zigachev 		return COLOR_DEPTH_666;
2256b843c749SSergey Zigachev 	case 8:
2257b843c749SSergey Zigachev 		return COLOR_DEPTH_888;
2258b843c749SSergey Zigachev 	case 10:
2259b843c749SSergey Zigachev 		return COLOR_DEPTH_101010;
2260b843c749SSergey Zigachev 	case 12:
2261b843c749SSergey Zigachev 		return COLOR_DEPTH_121212;
2262b843c749SSergey Zigachev 	case 14:
2263b843c749SSergey Zigachev 		return COLOR_DEPTH_141414;
2264b843c749SSergey Zigachev 	case 16:
2265b843c749SSergey Zigachev 		return COLOR_DEPTH_161616;
2266b843c749SSergey Zigachev 	default:
2267b843c749SSergey Zigachev 		return COLOR_DEPTH_UNDEFINED;
2268b843c749SSergey Zigachev 	}
2269b843c749SSergey Zigachev }
2270b843c749SSergey Zigachev 
2271b843c749SSergey Zigachev static enum dc_aspect_ratio
get_aspect_ratio(const struct drm_display_mode * mode_in)2272b843c749SSergey Zigachev get_aspect_ratio(const struct drm_display_mode *mode_in)
2273b843c749SSergey Zigachev {
2274b843c749SSergey Zigachev 	/* 1-1 mapping, since both enums follow the HDMI spec. */
2275b843c749SSergey Zigachev 	return (enum dc_aspect_ratio) mode_in->picture_aspect_ratio;
2276b843c749SSergey Zigachev }
2277b843c749SSergey Zigachev 
2278b843c749SSergey Zigachev static enum dc_color_space
get_output_color_space(const struct dc_crtc_timing * dc_crtc_timing)2279b843c749SSergey Zigachev get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing)
2280b843c749SSergey Zigachev {
2281b843c749SSergey Zigachev 	enum dc_color_space color_space = COLOR_SPACE_SRGB;
2282b843c749SSergey Zigachev 
2283b843c749SSergey Zigachev 	switch (dc_crtc_timing->pixel_encoding)	{
2284b843c749SSergey Zigachev 	case PIXEL_ENCODING_YCBCR422:
2285b843c749SSergey Zigachev 	case PIXEL_ENCODING_YCBCR444:
2286b843c749SSergey Zigachev 	case PIXEL_ENCODING_YCBCR420:
2287b843c749SSergey Zigachev 	{
2288b843c749SSergey Zigachev 		/*
2289b843c749SSergey Zigachev 		 * 27030khz is the separation point between HDTV and SDTV
2290b843c749SSergey Zigachev 		 * according to HDMI spec, we use YCbCr709 and YCbCr601
2291b843c749SSergey Zigachev 		 * respectively
2292b843c749SSergey Zigachev 		 */
2293b843c749SSergey Zigachev 		if (dc_crtc_timing->pix_clk_khz > 27030) {
2294b843c749SSergey Zigachev 			if (dc_crtc_timing->flags.Y_ONLY)
2295b843c749SSergey Zigachev 				color_space =
2296b843c749SSergey Zigachev 					COLOR_SPACE_YCBCR709_LIMITED;
2297b843c749SSergey Zigachev 			else
2298b843c749SSergey Zigachev 				color_space = COLOR_SPACE_YCBCR709;
2299b843c749SSergey Zigachev 		} else {
2300b843c749SSergey Zigachev 			if (dc_crtc_timing->flags.Y_ONLY)
2301b843c749SSergey Zigachev 				color_space =
2302b843c749SSergey Zigachev 					COLOR_SPACE_YCBCR601_LIMITED;
2303b843c749SSergey Zigachev 			else
2304b843c749SSergey Zigachev 				color_space = COLOR_SPACE_YCBCR601;
2305b843c749SSergey Zigachev 		}
2306b843c749SSergey Zigachev 
2307b843c749SSergey Zigachev 	}
2308b843c749SSergey Zigachev 	break;
2309b843c749SSergey Zigachev 	case PIXEL_ENCODING_RGB:
2310b843c749SSergey Zigachev 		color_space = COLOR_SPACE_SRGB;
2311b843c749SSergey Zigachev 		break;
2312b843c749SSergey Zigachev 
2313b843c749SSergey Zigachev 	default:
2314b843c749SSergey Zigachev 		WARN_ON(1);
2315b843c749SSergey Zigachev 		break;
2316b843c749SSergey Zigachev 	}
2317b843c749SSergey Zigachev 
2318b843c749SSergey Zigachev 	return color_space;
2319b843c749SSergey Zigachev }
2320b843c749SSergey Zigachev 
reduce_mode_colour_depth(struct dc_crtc_timing * timing_out)2321b843c749SSergey Zigachev static void reduce_mode_colour_depth(struct dc_crtc_timing *timing_out)
2322b843c749SSergey Zigachev {
2323b843c749SSergey Zigachev 	if (timing_out->display_color_depth <= COLOR_DEPTH_888)
2324b843c749SSergey Zigachev 		return;
2325b843c749SSergey Zigachev 
2326b843c749SSergey Zigachev 	timing_out->display_color_depth--;
2327b843c749SSergey Zigachev }
2328b843c749SSergey Zigachev 
adjust_colour_depth_from_display_info(struct dc_crtc_timing * timing_out,const struct drm_display_info * info)2329b843c749SSergey Zigachev static void adjust_colour_depth_from_display_info(struct dc_crtc_timing *timing_out,
2330b843c749SSergey Zigachev 						const struct drm_display_info *info)
2331b843c749SSergey Zigachev {
2332b843c749SSergey Zigachev 	int normalized_clk;
2333b843c749SSergey Zigachev 	if (timing_out->display_color_depth <= COLOR_DEPTH_888)
2334b843c749SSergey Zigachev 		return;
2335b843c749SSergey Zigachev 	do {
2336b843c749SSergey Zigachev 		normalized_clk = timing_out->pix_clk_khz;
2337b843c749SSergey Zigachev 		/* YCbCr 4:2:0 requires additional adjustment of 1/2 */
2338b843c749SSergey Zigachev 		if (timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420)
2339b843c749SSergey Zigachev 			normalized_clk /= 2;
2340b843c749SSergey Zigachev 		/* Adjusting pix clock following on HDMI spec based on colour depth */
2341b843c749SSergey Zigachev 		switch (timing_out->display_color_depth) {
2342b843c749SSergey Zigachev 		case COLOR_DEPTH_101010:
2343b843c749SSergey Zigachev 			normalized_clk = (normalized_clk * 30) / 24;
2344b843c749SSergey Zigachev 			break;
2345b843c749SSergey Zigachev 		case COLOR_DEPTH_121212:
2346b843c749SSergey Zigachev 			normalized_clk = (normalized_clk * 36) / 24;
2347b843c749SSergey Zigachev 			break;
2348b843c749SSergey Zigachev 		case COLOR_DEPTH_161616:
2349b843c749SSergey Zigachev 			normalized_clk = (normalized_clk * 48) / 24;
2350b843c749SSergey Zigachev 			break;
2351b843c749SSergey Zigachev 		default:
2352b843c749SSergey Zigachev 			return;
2353b843c749SSergey Zigachev 		}
2354b843c749SSergey Zigachev 		if (normalized_clk <= info->max_tmds_clock)
2355b843c749SSergey Zigachev 			return;
2356b843c749SSergey Zigachev 		reduce_mode_colour_depth(timing_out);
2357b843c749SSergey Zigachev 
2358b843c749SSergey Zigachev 	} while (timing_out->display_color_depth > COLOR_DEPTH_888);
2359b843c749SSergey Zigachev 
2360b843c749SSergey Zigachev }
2361b843c749SSergey Zigachev /*****************************************************************************/
2362b843c749SSergey Zigachev 
2363b843c749SSergey Zigachev static void
fill_stream_properties_from_drm_display_mode(struct dc_stream_state * stream,const struct drm_display_mode * mode_in,const struct drm_connector * connector)2364b843c749SSergey Zigachev fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream,
2365b843c749SSergey Zigachev 					     const struct drm_display_mode *mode_in,
2366b843c749SSergey Zigachev 					     const struct drm_connector *connector)
2367b843c749SSergey Zigachev {
2368b843c749SSergey Zigachev 	struct dc_crtc_timing *timing_out = &stream->timing;
2369b843c749SSergey Zigachev 	const struct drm_display_info *info = &connector->display_info;
2370b843c749SSergey Zigachev 
2371b843c749SSergey Zigachev 	memset(timing_out, 0, sizeof(struct dc_crtc_timing));
2372b843c749SSergey Zigachev 
2373b843c749SSergey Zigachev 	timing_out->h_border_left = 0;
2374b843c749SSergey Zigachev 	timing_out->h_border_right = 0;
2375b843c749SSergey Zigachev 	timing_out->v_border_top = 0;
2376b843c749SSergey Zigachev 	timing_out->v_border_bottom = 0;
2377b843c749SSergey Zigachev 	/* TODO: un-hardcode */
2378b843c749SSergey Zigachev 	if (drm_mode_is_420_only(info, mode_in)
2379b843c749SSergey Zigachev 			&& stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A)
2380b843c749SSergey Zigachev 		timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
2381b843c749SSergey Zigachev 	else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB444)
2382b843c749SSergey Zigachev 			&& stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A)
2383b843c749SSergey Zigachev 		timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444;
2384b843c749SSergey Zigachev 	else
2385b843c749SSergey Zigachev 		timing_out->pixel_encoding = PIXEL_ENCODING_RGB;
2386b843c749SSergey Zigachev 
2387b843c749SSergey Zigachev 	timing_out->timing_3d_format = TIMING_3D_FORMAT_NONE;
2388b843c749SSergey Zigachev 	timing_out->display_color_depth = convert_color_depth_from_display_info(
2389b843c749SSergey Zigachev 			connector);
2390b843c749SSergey Zigachev 	timing_out->scan_type = SCANNING_TYPE_NODATA;
2391b843c749SSergey Zigachev 	timing_out->hdmi_vic = 0;
2392b843c749SSergey Zigachev 	timing_out->vic = drm_match_cea_mode(mode_in);
2393b843c749SSergey Zigachev 
2394b843c749SSergey Zigachev 	timing_out->h_addressable = mode_in->crtc_hdisplay;
2395b843c749SSergey Zigachev 	timing_out->h_total = mode_in->crtc_htotal;
2396b843c749SSergey Zigachev 	timing_out->h_sync_width =
2397b843c749SSergey Zigachev 		mode_in->crtc_hsync_end - mode_in->crtc_hsync_start;
2398b843c749SSergey Zigachev 	timing_out->h_front_porch =
2399b843c749SSergey Zigachev 		mode_in->crtc_hsync_start - mode_in->crtc_hdisplay;
2400b843c749SSergey Zigachev 	timing_out->v_total = mode_in->crtc_vtotal;
2401b843c749SSergey Zigachev 	timing_out->v_addressable = mode_in->crtc_vdisplay;
2402b843c749SSergey Zigachev 	timing_out->v_front_porch =
2403b843c749SSergey Zigachev 		mode_in->crtc_vsync_start - mode_in->crtc_vdisplay;
2404b843c749SSergey Zigachev 	timing_out->v_sync_width =
2405b843c749SSergey Zigachev 		mode_in->crtc_vsync_end - mode_in->crtc_vsync_start;
2406b843c749SSergey Zigachev 	timing_out->pix_clk_khz = mode_in->crtc_clock;
2407b843c749SSergey Zigachev 	timing_out->aspect_ratio = get_aspect_ratio(mode_in);
2408b843c749SSergey Zigachev 	if (mode_in->flags & DRM_MODE_FLAG_PHSYNC)
2409b843c749SSergey Zigachev 		timing_out->flags.HSYNC_POSITIVE_POLARITY = 1;
2410b843c749SSergey Zigachev 	if (mode_in->flags & DRM_MODE_FLAG_PVSYNC)
2411b843c749SSergey Zigachev 		timing_out->flags.VSYNC_POSITIVE_POLARITY = 1;
2412b843c749SSergey Zigachev 
2413b843c749SSergey Zigachev 	stream->output_color_space = get_output_color_space(timing_out);
2414b843c749SSergey Zigachev 
2415b843c749SSergey Zigachev 	stream->out_transfer_func->type = TF_TYPE_PREDEFINED;
2416b843c749SSergey Zigachev 	stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB;
2417b843c749SSergey Zigachev 	if (stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A)
2418b843c749SSergey Zigachev 		adjust_colour_depth_from_display_info(timing_out, info);
2419b843c749SSergey Zigachev }
2420b843c749SSergey Zigachev 
fill_audio_info(struct audio_info * audio_info,const struct drm_connector * drm_connector,const struct dc_sink * dc_sink)2421b843c749SSergey Zigachev static void fill_audio_info(struct audio_info *audio_info,
2422b843c749SSergey Zigachev 			    const struct drm_connector *drm_connector,
2423b843c749SSergey Zigachev 			    const struct dc_sink *dc_sink)
2424b843c749SSergey Zigachev {
2425b843c749SSergey Zigachev 	int i = 0;
2426b843c749SSergey Zigachev 	int cea_revision = 0;
2427b843c749SSergey Zigachev 	const struct dc_edid_caps *edid_caps = &dc_sink->edid_caps;
2428b843c749SSergey Zigachev 
2429b843c749SSergey Zigachev 	audio_info->manufacture_id = edid_caps->manufacturer_id;
2430b843c749SSergey Zigachev 	audio_info->product_id = edid_caps->product_id;
2431b843c749SSergey Zigachev 
2432b843c749SSergey Zigachev 	cea_revision = drm_connector->display_info.cea_rev;
2433b843c749SSergey Zigachev 
2434b843c749SSergey Zigachev 	strncpy(audio_info->display_name,
2435b843c749SSergey Zigachev 		edid_caps->display_name,
2436b843c749SSergey Zigachev 		AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS - 1);
2437b843c749SSergey Zigachev 
2438b843c749SSergey Zigachev 	if (cea_revision >= 3) {
2439b843c749SSergey Zigachev 		audio_info->mode_count = edid_caps->audio_mode_count;
2440b843c749SSergey Zigachev 
2441b843c749SSergey Zigachev 		for (i = 0; i < audio_info->mode_count; ++i) {
2442b843c749SSergey Zigachev 			audio_info->modes[i].format_code =
2443b843c749SSergey Zigachev 					(enum audio_format_code)
2444b843c749SSergey Zigachev 					(edid_caps->audio_modes[i].format_code);
2445b843c749SSergey Zigachev 			audio_info->modes[i].channel_count =
2446b843c749SSergey Zigachev 					edid_caps->audio_modes[i].channel_count;
2447b843c749SSergey Zigachev 			audio_info->modes[i].sample_rates.all =
2448b843c749SSergey Zigachev 					edid_caps->audio_modes[i].sample_rate;
2449b843c749SSergey Zigachev 			audio_info->modes[i].sample_size =
2450b843c749SSergey Zigachev 					edid_caps->audio_modes[i].sample_size;
2451b843c749SSergey Zigachev 		}
2452b843c749SSergey Zigachev 	}
2453b843c749SSergey Zigachev 
2454b843c749SSergey Zigachev 	audio_info->flags.all = edid_caps->speaker_flags;
2455b843c749SSergey Zigachev 
2456b843c749SSergey Zigachev 	/* TODO: We only check for the progressive mode, check for interlace mode too */
2457b843c749SSergey Zigachev 	if (drm_connector->latency_present[0]) {
2458b843c749SSergey Zigachev 		audio_info->video_latency = drm_connector->video_latency[0];
2459b843c749SSergey Zigachev 		audio_info->audio_latency = drm_connector->audio_latency[0];
2460b843c749SSergey Zigachev 	}
2461b843c749SSergey Zigachev 
2462b843c749SSergey Zigachev 	/* TODO: For DP, video and audio latency should be calculated from DPCD caps */
2463b843c749SSergey Zigachev 
2464b843c749SSergey Zigachev }
2465b843c749SSergey Zigachev 
2466b843c749SSergey Zigachev static void
copy_crtc_timing_for_drm_display_mode(const struct drm_display_mode * src_mode,struct drm_display_mode * dst_mode)2467b843c749SSergey Zigachev copy_crtc_timing_for_drm_display_mode(const struct drm_display_mode *src_mode,
2468b843c749SSergey Zigachev 				      struct drm_display_mode *dst_mode)
2469b843c749SSergey Zigachev {
2470b843c749SSergey Zigachev 	dst_mode->crtc_hdisplay = src_mode->crtc_hdisplay;
2471b843c749SSergey Zigachev 	dst_mode->crtc_vdisplay = src_mode->crtc_vdisplay;
2472b843c749SSergey Zigachev 	dst_mode->crtc_clock = src_mode->crtc_clock;
2473b843c749SSergey Zigachev 	dst_mode->crtc_hblank_start = src_mode->crtc_hblank_start;
2474b843c749SSergey Zigachev 	dst_mode->crtc_hblank_end = src_mode->crtc_hblank_end;
2475b843c749SSergey Zigachev 	dst_mode->crtc_hsync_start =  src_mode->crtc_hsync_start;
2476b843c749SSergey Zigachev 	dst_mode->crtc_hsync_end = src_mode->crtc_hsync_end;
2477b843c749SSergey Zigachev 	dst_mode->crtc_htotal = src_mode->crtc_htotal;
2478b843c749SSergey Zigachev 	dst_mode->crtc_hskew = src_mode->crtc_hskew;
2479b843c749SSergey Zigachev 	dst_mode->crtc_vblank_start = src_mode->crtc_vblank_start;
2480b843c749SSergey Zigachev 	dst_mode->crtc_vblank_end = src_mode->crtc_vblank_end;
2481b843c749SSergey Zigachev 	dst_mode->crtc_vsync_start = src_mode->crtc_vsync_start;
2482b843c749SSergey Zigachev 	dst_mode->crtc_vsync_end = src_mode->crtc_vsync_end;
2483b843c749SSergey Zigachev 	dst_mode->crtc_vtotal = src_mode->crtc_vtotal;
2484b843c749SSergey Zigachev }
2485b843c749SSergey Zigachev 
2486b843c749SSergey Zigachev static void
decide_crtc_timing_for_drm_display_mode(struct drm_display_mode * drm_mode,const struct drm_display_mode * native_mode,bool scale_enabled)2487b843c749SSergey Zigachev decide_crtc_timing_for_drm_display_mode(struct drm_display_mode *drm_mode,
2488b843c749SSergey Zigachev 					const struct drm_display_mode *native_mode,
2489b843c749SSergey Zigachev 					bool scale_enabled)
2490b843c749SSergey Zigachev {
2491b843c749SSergey Zigachev 	if (scale_enabled) {
2492b843c749SSergey Zigachev 		copy_crtc_timing_for_drm_display_mode(native_mode, drm_mode);
2493b843c749SSergey Zigachev 	} else if (native_mode->clock == drm_mode->clock &&
2494b843c749SSergey Zigachev 			native_mode->htotal == drm_mode->htotal &&
2495b843c749SSergey Zigachev 			native_mode->vtotal == drm_mode->vtotal) {
2496b843c749SSergey Zigachev 		copy_crtc_timing_for_drm_display_mode(native_mode, drm_mode);
2497b843c749SSergey Zigachev 	} else {
2498b843c749SSergey Zigachev 		/* no scaling nor amdgpu inserted, no need to patch */
2499b843c749SSergey Zigachev 	}
2500b843c749SSergey Zigachev }
2501b843c749SSergey Zigachev 
2502b843c749SSergey Zigachev static struct dc_sink *
create_fake_sink(struct amdgpu_dm_connector * aconnector)2503b843c749SSergey Zigachev create_fake_sink(struct amdgpu_dm_connector *aconnector)
2504b843c749SSergey Zigachev {
2505b843c749SSergey Zigachev 	struct dc_sink_init_data sink_init_data = { 0 };
2506b843c749SSergey Zigachev 	struct dc_sink *sink = NULL;
2507b843c749SSergey Zigachev 	sink_init_data.link = aconnector->dc_link;
2508b843c749SSergey Zigachev 	sink_init_data.sink_signal = aconnector->dc_link->connector_signal;
2509b843c749SSergey Zigachev 
2510b843c749SSergey Zigachev 	sink = dc_sink_create(&sink_init_data);
2511b843c749SSergey Zigachev 	if (!sink) {
2512b843c749SSergey Zigachev 		DRM_ERROR("Failed to create sink!\n");
2513b843c749SSergey Zigachev 		return NULL;
2514b843c749SSergey Zigachev 	}
2515b843c749SSergey Zigachev 	sink->sink_signal = SIGNAL_TYPE_VIRTUAL;
2516b843c749SSergey Zigachev 
2517b843c749SSergey Zigachev 	return sink;
2518b843c749SSergey Zigachev }
2519b843c749SSergey Zigachev 
set_multisync_trigger_params(struct dc_stream_state * stream)2520b843c749SSergey Zigachev static void set_multisync_trigger_params(
2521b843c749SSergey Zigachev 		struct dc_stream_state *stream)
2522b843c749SSergey Zigachev {
2523b843c749SSergey Zigachev 	if (stream->triggered_crtc_reset.enabled) {
2524b843c749SSergey Zigachev 		stream->triggered_crtc_reset.event = CRTC_EVENT_VSYNC_RISING;
2525b843c749SSergey Zigachev 		stream->triggered_crtc_reset.delay = TRIGGER_DELAY_NEXT_LINE;
2526b843c749SSergey Zigachev 	}
2527b843c749SSergey Zigachev }
2528b843c749SSergey Zigachev 
set_master_stream(struct dc_stream_state * stream_set[],int stream_count)2529b843c749SSergey Zigachev static void set_master_stream(struct dc_stream_state *stream_set[],
2530b843c749SSergey Zigachev 			      int stream_count)
2531b843c749SSergey Zigachev {
2532b843c749SSergey Zigachev 	int j, highest_rfr = 0, master_stream = 0;
2533b843c749SSergey Zigachev 
2534b843c749SSergey Zigachev 	for (j = 0;  j < stream_count; j++) {
2535b843c749SSergey Zigachev 		if (stream_set[j] && stream_set[j]->triggered_crtc_reset.enabled) {
2536b843c749SSergey Zigachev 			int refresh_rate = 0;
2537b843c749SSergey Zigachev 
2538b843c749SSergey Zigachev 			refresh_rate = (stream_set[j]->timing.pix_clk_khz*1000)/
2539b843c749SSergey Zigachev 				(stream_set[j]->timing.h_total*stream_set[j]->timing.v_total);
2540b843c749SSergey Zigachev 			if (refresh_rate > highest_rfr) {
2541b843c749SSergey Zigachev 				highest_rfr = refresh_rate;
2542b843c749SSergey Zigachev 				master_stream = j;
2543b843c749SSergey Zigachev 			}
2544b843c749SSergey Zigachev 		}
2545b843c749SSergey Zigachev 	}
2546b843c749SSergey Zigachev 	for (j = 0;  j < stream_count; j++) {
2547b843c749SSergey Zigachev 		if (stream_set[j])
2548b843c749SSergey Zigachev 			stream_set[j]->triggered_crtc_reset.event_source = stream_set[master_stream];
2549b843c749SSergey Zigachev 	}
2550b843c749SSergey Zigachev }
2551b843c749SSergey Zigachev 
dm_enable_per_frame_crtc_master_sync(struct dc_state * context)2552b843c749SSergey Zigachev static void dm_enable_per_frame_crtc_master_sync(struct dc_state *context)
2553b843c749SSergey Zigachev {
2554b843c749SSergey Zigachev 	int i = 0;
2555b843c749SSergey Zigachev 
2556b843c749SSergey Zigachev 	if (context->stream_count < 2)
2557b843c749SSergey Zigachev 		return;
2558b843c749SSergey Zigachev 	for (i = 0; i < context->stream_count ; i++) {
2559b843c749SSergey Zigachev 		if (!context->streams[i])
2560b843c749SSergey Zigachev 			continue;
2561b843c749SSergey Zigachev 		/* TODO: add a function to read AMD VSDB bits and will set
2562b843c749SSergey Zigachev 		 * crtc_sync_master.multi_sync_enabled flag
2563b843c749SSergey Zigachev 		 * For now its set to false
2564b843c749SSergey Zigachev 		 */
2565b843c749SSergey Zigachev 		set_multisync_trigger_params(context->streams[i]);
2566b843c749SSergey Zigachev 	}
2567b843c749SSergey Zigachev 	set_master_stream(context->streams, context->stream_count);
2568b843c749SSergey Zigachev }
2569b843c749SSergey Zigachev 
2570b843c749SSergey Zigachev static struct dc_stream_state *
create_stream_for_sink(struct amdgpu_dm_connector * aconnector,const struct drm_display_mode * drm_mode,const struct dm_connector_state * dm_state)2571b843c749SSergey Zigachev create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
2572b843c749SSergey Zigachev 		       const struct drm_display_mode *drm_mode,
2573b843c749SSergey Zigachev 		       const struct dm_connector_state *dm_state)
2574b843c749SSergey Zigachev {
2575b843c749SSergey Zigachev 	struct drm_display_mode *preferred_mode = NULL;
2576b843c749SSergey Zigachev 	struct drm_connector *drm_connector;
2577b843c749SSergey Zigachev 	struct dc_stream_state *stream = NULL;
2578b843c749SSergey Zigachev 	struct drm_display_mode mode = *drm_mode;
2579b843c749SSergey Zigachev 	bool native_mode_found = false;
2580b843c749SSergey Zigachev 	struct dc_sink *sink = NULL;
2581b843c749SSergey Zigachev 	if (aconnector == NULL) {
2582b843c749SSergey Zigachev 		DRM_ERROR("aconnector is NULL!\n");
2583b843c749SSergey Zigachev 		return stream;
2584b843c749SSergey Zigachev 	}
2585b843c749SSergey Zigachev 
2586b843c749SSergey Zigachev 	drm_connector = &aconnector->base;
2587b843c749SSergey Zigachev 
2588b843c749SSergey Zigachev 	if (!aconnector->dc_sink) {
2589b843c749SSergey Zigachev 		/*
2590b843c749SSergey Zigachev 		 * Create dc_sink when necessary to MST
2591b843c749SSergey Zigachev 		 * Don't apply fake_sink to MST
2592b843c749SSergey Zigachev 		 */
2593b843c749SSergey Zigachev 		if (aconnector->mst_port) {
2594b843c749SSergey Zigachev 			dm_dp_mst_dc_sink_create(drm_connector);
2595b843c749SSergey Zigachev 			return stream;
2596b843c749SSergey Zigachev 		}
2597b843c749SSergey Zigachev 
2598b843c749SSergey Zigachev 		sink = create_fake_sink(aconnector);
2599b843c749SSergey Zigachev 		if (!sink)
2600b843c749SSergey Zigachev 			return stream;
2601b843c749SSergey Zigachev 	} else {
2602b843c749SSergey Zigachev 		sink = aconnector->dc_sink;
2603b843c749SSergey Zigachev 	}
2604b843c749SSergey Zigachev 
2605b843c749SSergey Zigachev 	stream = dc_create_stream_for_sink(sink);
2606b843c749SSergey Zigachev 
2607b843c749SSergey Zigachev 	if (stream == NULL) {
2608b843c749SSergey Zigachev 		DRM_ERROR("Failed to create stream for sink!\n");
2609b843c749SSergey Zigachev 		goto finish;
2610b843c749SSergey Zigachev 	}
2611b843c749SSergey Zigachev 
2612b843c749SSergey Zigachev 	list_for_each_entry(preferred_mode, &aconnector->base.modes, head) {
2613b843c749SSergey Zigachev 		/* Search for preferred mode */
2614b843c749SSergey Zigachev 		if (preferred_mode->type & DRM_MODE_TYPE_PREFERRED) {
2615b843c749SSergey Zigachev 			native_mode_found = true;
2616b843c749SSergey Zigachev 			break;
2617b843c749SSergey Zigachev 		}
2618b843c749SSergey Zigachev 	}
2619b843c749SSergey Zigachev 	if (!native_mode_found)
2620b843c749SSergey Zigachev 		preferred_mode = list_first_entry_or_null(
2621b843c749SSergey Zigachev 				&aconnector->base.modes,
2622b843c749SSergey Zigachev 				struct drm_display_mode,
2623b843c749SSergey Zigachev 				head);
2624b843c749SSergey Zigachev 
2625b843c749SSergey Zigachev 	if (preferred_mode == NULL) {
2626b843c749SSergey Zigachev 		/* This may not be an error, the use case is when we we have no
2627b843c749SSergey Zigachev 		 * usermode calls to reset and set mode upon hotplug. In this
2628b843c749SSergey Zigachev 		 * case, we call set mode ourselves to restore the previous mode
2629b843c749SSergey Zigachev 		 * and the modelist may not be filled in in time.
2630b843c749SSergey Zigachev 		 */
2631b843c749SSergey Zigachev 		DRM_DEBUG_DRIVER("No preferred mode found\n");
2632b843c749SSergey Zigachev 	} else {
2633b843c749SSergey Zigachev 		decide_crtc_timing_for_drm_display_mode(
2634b843c749SSergey Zigachev 				&mode, preferred_mode,
2635b843c749SSergey Zigachev 				dm_state ? (dm_state->scaling != RMX_OFF) : false);
2636b843c749SSergey Zigachev 	}
2637b843c749SSergey Zigachev 
2638b843c749SSergey Zigachev 	if (!dm_state)
2639b843c749SSergey Zigachev 		drm_mode_set_crtcinfo(&mode, 0);
2640b843c749SSergey Zigachev 
2641b843c749SSergey Zigachev 	fill_stream_properties_from_drm_display_mode(stream,
2642b843c749SSergey Zigachev 			&mode, &aconnector->base);
2643b843c749SSergey Zigachev 	update_stream_scaling_settings(&mode, dm_state, stream);
2644b843c749SSergey Zigachev 
2645b843c749SSergey Zigachev 	fill_audio_info(
2646b843c749SSergey Zigachev 		&stream->audio_info,
2647b843c749SSergey Zigachev 		drm_connector,
2648b843c749SSergey Zigachev 		sink);
2649b843c749SSergey Zigachev 
2650b843c749SSergey Zigachev 	update_stream_signal(stream);
2651b843c749SSergey Zigachev 
2652b843c749SSergey Zigachev 	if (dm_state && dm_state->freesync_capable)
2653b843c749SSergey Zigachev 		stream->ignore_msa_timing_param = true;
2654b843c749SSergey Zigachev finish:
2655b843c749SSergey Zigachev 	if (sink && sink->sink_signal == SIGNAL_TYPE_VIRTUAL && aconnector->base.force != DRM_FORCE_ON)
2656b843c749SSergey Zigachev 		dc_sink_release(sink);
2657b843c749SSergey Zigachev 
2658b843c749SSergey Zigachev 	return stream;
2659b843c749SSergey Zigachev }
2660b843c749SSergey Zigachev 
amdgpu_dm_crtc_destroy(struct drm_crtc * crtc)2661b843c749SSergey Zigachev static void amdgpu_dm_crtc_destroy(struct drm_crtc *crtc)
2662b843c749SSergey Zigachev {
2663b843c749SSergey Zigachev 	drm_crtc_cleanup(crtc);
2664b843c749SSergey Zigachev 	kfree(crtc);
2665b843c749SSergey Zigachev }
2666b843c749SSergey Zigachev 
dm_crtc_destroy_state(struct drm_crtc * crtc,struct drm_crtc_state * state)2667b843c749SSergey Zigachev static void dm_crtc_destroy_state(struct drm_crtc *crtc,
2668b843c749SSergey Zigachev 				  struct drm_crtc_state *state)
2669b843c749SSergey Zigachev {
2670b843c749SSergey Zigachev 	struct dm_crtc_state *cur = to_dm_crtc_state(state);
2671b843c749SSergey Zigachev 
2672b843c749SSergey Zigachev 	/* TODO Destroy dc_stream objects are stream object is flattened */
2673b843c749SSergey Zigachev 	if (cur->stream)
2674b843c749SSergey Zigachev 		dc_stream_release(cur->stream);
2675b843c749SSergey Zigachev 
2676b843c749SSergey Zigachev 
2677b843c749SSergey Zigachev 	__drm_atomic_helper_crtc_destroy_state(state);
2678b843c749SSergey Zigachev 
2679b843c749SSergey Zigachev 
2680b843c749SSergey Zigachev 	kfree(state);
2681b843c749SSergey Zigachev }
2682b843c749SSergey Zigachev 
dm_crtc_reset_state(struct drm_crtc * crtc)2683b843c749SSergey Zigachev static void dm_crtc_reset_state(struct drm_crtc *crtc)
2684b843c749SSergey Zigachev {
2685b843c749SSergey Zigachev 	struct dm_crtc_state *state;
2686b843c749SSergey Zigachev 
2687b843c749SSergey Zigachev 	if (crtc->state)
2688b843c749SSergey Zigachev 		dm_crtc_destroy_state(crtc, crtc->state);
2689b843c749SSergey Zigachev 
2690b843c749SSergey Zigachev 	state = kzalloc(sizeof(*state), GFP_KERNEL);
2691b843c749SSergey Zigachev 	if (WARN_ON(!state))
2692b843c749SSergey Zigachev 		return;
2693b843c749SSergey Zigachev 
2694b843c749SSergey Zigachev 	crtc->state = &state->base;
2695b843c749SSergey Zigachev 	crtc->state->crtc = crtc;
2696b843c749SSergey Zigachev 
2697b843c749SSergey Zigachev }
2698b843c749SSergey Zigachev 
2699b843c749SSergey Zigachev static struct drm_crtc_state *
dm_crtc_duplicate_state(struct drm_crtc * crtc)2700b843c749SSergey Zigachev dm_crtc_duplicate_state(struct drm_crtc *crtc)
2701b843c749SSergey Zigachev {
2702b843c749SSergey Zigachev 	struct dm_crtc_state *state, *cur;
2703b843c749SSergey Zigachev 
2704b843c749SSergey Zigachev 	cur = to_dm_crtc_state(crtc->state);
2705b843c749SSergey Zigachev 
2706b843c749SSergey Zigachev 	if (WARN_ON(!crtc->state))
2707b843c749SSergey Zigachev 		return NULL;
2708b843c749SSergey Zigachev 
2709b843c749SSergey Zigachev 	state = kzalloc(sizeof(*state), GFP_KERNEL);
2710b843c749SSergey Zigachev 	if (!state)
2711b843c749SSergey Zigachev 		return NULL;
2712b843c749SSergey Zigachev 
2713b843c749SSergey Zigachev 	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
2714b843c749SSergey Zigachev 
2715b843c749SSergey Zigachev 	if (cur->stream) {
2716b843c749SSergey Zigachev 		state->stream = cur->stream;
2717b843c749SSergey Zigachev 		dc_stream_retain(state->stream);
2718b843c749SSergey Zigachev 	}
2719b843c749SSergey Zigachev 
2720b843c749SSergey Zigachev 	/* TODO Duplicate dc_stream after objects are stream object is flattened */
2721b843c749SSergey Zigachev 
2722b843c749SSergey Zigachev 	return &state->base;
2723b843c749SSergey Zigachev }
2724b843c749SSergey Zigachev 
2725b843c749SSergey Zigachev 
dm_set_vblank(struct drm_crtc * crtc,bool enable)2726b843c749SSergey Zigachev static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable)
2727b843c749SSergey Zigachev {
2728b843c749SSergey Zigachev 	enum dc_irq_source irq_source;
2729b843c749SSergey Zigachev 	struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
2730b843c749SSergey Zigachev 	struct amdgpu_device *adev = crtc->dev->dev_private;
2731b843c749SSergey Zigachev 
2732b843c749SSergey Zigachev 	irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst;
2733b843c749SSergey Zigachev 	return dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
2734b843c749SSergey Zigachev }
2735b843c749SSergey Zigachev 
dm_enable_vblank(struct drm_crtc * crtc)2736b843c749SSergey Zigachev static int dm_enable_vblank(struct drm_crtc *crtc)
2737b843c749SSergey Zigachev {
2738b843c749SSergey Zigachev 	return dm_set_vblank(crtc, true);
2739b843c749SSergey Zigachev }
2740b843c749SSergey Zigachev 
dm_disable_vblank(struct drm_crtc * crtc)2741b843c749SSergey Zigachev static void dm_disable_vblank(struct drm_crtc *crtc)
2742b843c749SSergey Zigachev {
2743b843c749SSergey Zigachev 	dm_set_vblank(crtc, false);
2744b843c749SSergey Zigachev }
2745b843c749SSergey Zigachev 
2746b843c749SSergey Zigachev /* Implemented only the options currently availible for the driver */
2747b843c749SSergey Zigachev static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = {
2748b843c749SSergey Zigachev 	.reset = dm_crtc_reset_state,
2749b843c749SSergey Zigachev 	.destroy = amdgpu_dm_crtc_destroy,
2750b843c749SSergey Zigachev 	.gamma_set = drm_atomic_helper_legacy_gamma_set,
2751b843c749SSergey Zigachev 	.set_config = drm_atomic_helper_set_config,
2752b843c749SSergey Zigachev 	.page_flip = drm_atomic_helper_page_flip,
2753b843c749SSergey Zigachev 	.atomic_duplicate_state = dm_crtc_duplicate_state,
2754b843c749SSergey Zigachev 	.atomic_destroy_state = dm_crtc_destroy_state,
2755b843c749SSergey Zigachev 	.set_crc_source = amdgpu_dm_crtc_set_crc_source,
2756b843c749SSergey Zigachev 	.enable_vblank = dm_enable_vblank,
2757b843c749SSergey Zigachev 	.disable_vblank = dm_disable_vblank,
2758b843c749SSergey Zigachev };
2759b843c749SSergey Zigachev 
2760b843c749SSergey Zigachev static enum drm_connector_status
amdgpu_dm_connector_detect(struct drm_connector * connector,bool force)2761b843c749SSergey Zigachev amdgpu_dm_connector_detect(struct drm_connector *connector, bool force)
2762b843c749SSergey Zigachev {
2763b843c749SSergey Zigachev 	bool connected;
2764b843c749SSergey Zigachev 	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
2765b843c749SSergey Zigachev 
2766b843c749SSergey Zigachev 	/* Notes:
2767b843c749SSergey Zigachev 	 * 1. This interface is NOT called in context of HPD irq.
2768b843c749SSergey Zigachev 	 * 2. This interface *is called* in context of user-mode ioctl. Which
2769b843c749SSergey Zigachev 	 * makes it a bad place for *any* MST-related activit. */
2770b843c749SSergey Zigachev 
2771b843c749SSergey Zigachev 	if (aconnector->base.force == DRM_FORCE_UNSPECIFIED &&
2772b843c749SSergey Zigachev 	    !aconnector->fake_enable)
2773b843c749SSergey Zigachev 		connected = (aconnector->dc_sink != NULL);
2774b843c749SSergey Zigachev 	else
2775b843c749SSergey Zigachev 		connected = (aconnector->base.force == DRM_FORCE_ON);
2776b843c749SSergey Zigachev 
2777b843c749SSergey Zigachev 	return (connected ? connector_status_connected :
2778b843c749SSergey Zigachev 			connector_status_disconnected);
2779b843c749SSergey Zigachev }
2780b843c749SSergey Zigachev 
amdgpu_dm_connector_atomic_set_property(struct drm_connector * connector,struct drm_connector_state * connector_state,struct drm_property * property,uint64_t val)2781b843c749SSergey Zigachev int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector,
2782b843c749SSergey Zigachev 					    struct drm_connector_state *connector_state,
2783b843c749SSergey Zigachev 					    struct drm_property *property,
2784b843c749SSergey Zigachev 					    uint64_t val)
2785b843c749SSergey Zigachev {
2786b843c749SSergey Zigachev 	struct drm_device *dev = connector->dev;
2787b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev->dev_private;
2788b843c749SSergey Zigachev 	struct dm_connector_state *dm_old_state =
2789b843c749SSergey Zigachev 		to_dm_connector_state(connector->state);
2790b843c749SSergey Zigachev 	struct dm_connector_state *dm_new_state =
2791b843c749SSergey Zigachev 		to_dm_connector_state(connector_state);
2792b843c749SSergey Zigachev 
2793b843c749SSergey Zigachev 	int ret = -EINVAL;
2794b843c749SSergey Zigachev 
2795b843c749SSergey Zigachev 	if (property == dev->mode_config.scaling_mode_property) {
2796b843c749SSergey Zigachev 		enum amdgpu_rmx_type rmx_type;
2797b843c749SSergey Zigachev 
2798b843c749SSergey Zigachev 		switch (val) {
2799b843c749SSergey Zigachev 		case DRM_MODE_SCALE_CENTER:
2800b843c749SSergey Zigachev 			rmx_type = RMX_CENTER;
2801b843c749SSergey Zigachev 			break;
2802b843c749SSergey Zigachev 		case DRM_MODE_SCALE_ASPECT:
2803b843c749SSergey Zigachev 			rmx_type = RMX_ASPECT;
2804b843c749SSergey Zigachev 			break;
2805b843c749SSergey Zigachev 		case DRM_MODE_SCALE_FULLSCREEN:
2806b843c749SSergey Zigachev 			rmx_type = RMX_FULL;
2807b843c749SSergey Zigachev 			break;
2808b843c749SSergey Zigachev 		case DRM_MODE_SCALE_NONE:
2809b843c749SSergey Zigachev 		default:
2810b843c749SSergey Zigachev 			rmx_type = RMX_OFF;
2811b843c749SSergey Zigachev 			break;
2812b843c749SSergey Zigachev 		}
2813b843c749SSergey Zigachev 
2814b843c749SSergey Zigachev 		if (dm_old_state->scaling == rmx_type)
2815b843c749SSergey Zigachev 			return 0;
2816b843c749SSergey Zigachev 
2817b843c749SSergey Zigachev 		dm_new_state->scaling = rmx_type;
2818b843c749SSergey Zigachev 		ret = 0;
2819b843c749SSergey Zigachev 	} else if (property == adev->mode_info.underscan_hborder_property) {
2820b843c749SSergey Zigachev 		dm_new_state->underscan_hborder = val;
2821b843c749SSergey Zigachev 		ret = 0;
2822b843c749SSergey Zigachev 	} else if (property == adev->mode_info.underscan_vborder_property) {
2823b843c749SSergey Zigachev 		dm_new_state->underscan_vborder = val;
2824b843c749SSergey Zigachev 		ret = 0;
2825b843c749SSergey Zigachev 	} else if (property == adev->mode_info.underscan_property) {
2826b843c749SSergey Zigachev 		dm_new_state->underscan_enable = val;
2827b843c749SSergey Zigachev 		ret = 0;
2828b843c749SSergey Zigachev 	} else if (property == adev->mode_info.max_bpc_property) {
2829b843c749SSergey Zigachev 		dm_new_state->max_bpc = val;
2830b843c749SSergey Zigachev 		ret = 0;
2831b843c749SSergey Zigachev 	}
2832b843c749SSergey Zigachev 
2833b843c749SSergey Zigachev 	return ret;
2834b843c749SSergey Zigachev }
2835b843c749SSergey Zigachev 
amdgpu_dm_connector_atomic_get_property(struct drm_connector * connector,const struct drm_connector_state * state,struct drm_property * property,uint64_t * val)2836b843c749SSergey Zigachev int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector,
2837b843c749SSergey Zigachev 					    const struct drm_connector_state *state,
2838b843c749SSergey Zigachev 					    struct drm_property *property,
2839b843c749SSergey Zigachev 					    uint64_t *val)
2840b843c749SSergey Zigachev {
2841b843c749SSergey Zigachev 	struct drm_device *dev = connector->dev;
2842b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev->dev_private;
2843b843c749SSergey Zigachev 	struct dm_connector_state *dm_state =
2844b843c749SSergey Zigachev 		to_dm_connector_state(state);
2845b843c749SSergey Zigachev 	int ret = -EINVAL;
2846b843c749SSergey Zigachev 
2847b843c749SSergey Zigachev 	if (property == dev->mode_config.scaling_mode_property) {
2848b843c749SSergey Zigachev 		switch (dm_state->scaling) {
2849b843c749SSergey Zigachev 		case RMX_CENTER:
2850b843c749SSergey Zigachev 			*val = DRM_MODE_SCALE_CENTER;
2851b843c749SSergey Zigachev 			break;
2852b843c749SSergey Zigachev 		case RMX_ASPECT:
2853b843c749SSergey Zigachev 			*val = DRM_MODE_SCALE_ASPECT;
2854b843c749SSergey Zigachev 			break;
2855b843c749SSergey Zigachev 		case RMX_FULL:
2856b843c749SSergey Zigachev 			*val = DRM_MODE_SCALE_FULLSCREEN;
2857b843c749SSergey Zigachev 			break;
2858b843c749SSergey Zigachev 		case RMX_OFF:
2859b843c749SSergey Zigachev 		default:
2860b843c749SSergey Zigachev 			*val = DRM_MODE_SCALE_NONE;
2861b843c749SSergey Zigachev 			break;
2862b843c749SSergey Zigachev 		}
2863b843c749SSergey Zigachev 		ret = 0;
2864b843c749SSergey Zigachev 	} else if (property == adev->mode_info.underscan_hborder_property) {
2865b843c749SSergey Zigachev 		*val = dm_state->underscan_hborder;
2866b843c749SSergey Zigachev 		ret = 0;
2867b843c749SSergey Zigachev 	} else if (property == adev->mode_info.underscan_vborder_property) {
2868b843c749SSergey Zigachev 		*val = dm_state->underscan_vborder;
2869b843c749SSergey Zigachev 		ret = 0;
2870b843c749SSergey Zigachev 	} else if (property == adev->mode_info.underscan_property) {
2871b843c749SSergey Zigachev 		*val = dm_state->underscan_enable;
2872b843c749SSergey Zigachev 		ret = 0;
2873b843c749SSergey Zigachev 	} else if (property == adev->mode_info.max_bpc_property) {
2874b843c749SSergey Zigachev 		*val = dm_state->max_bpc;
2875b843c749SSergey Zigachev 		ret = 0;
2876b843c749SSergey Zigachev 	}
2877b843c749SSergey Zigachev 	return ret;
2878b843c749SSergey Zigachev }
2879b843c749SSergey Zigachev 
amdgpu_dm_connector_destroy(struct drm_connector * connector)2880b843c749SSergey Zigachev static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
2881b843c749SSergey Zigachev {
2882b843c749SSergey Zigachev 	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
2883b843c749SSergey Zigachev 	const struct dc_link *link = aconnector->dc_link;
2884b843c749SSergey Zigachev 	struct amdgpu_device *adev = connector->dev->dev_private;
2885b843c749SSergey Zigachev 	struct amdgpu_display_manager *dm = &adev->dm;
2886b843c749SSergey Zigachev 
2887b843c749SSergey Zigachev #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\
2888b843c749SSergey Zigachev 	defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
2889b843c749SSergey Zigachev 	if ((link->connector_signal & (SIGNAL_TYPE_EDP | SIGNAL_TYPE_LVDS)) &&
2890b843c749SSergey Zigachev 	    link->type != dc_connection_none &&
2891b843c749SSergey Zigachev 	    dm->backlight_dev) {
2892*78973132SSergey Zigachev #if 0
2893b843c749SSergey Zigachev 		backlight_device_unregister(dm->backlight_dev);
2894*78973132SSergey Zigachev #endif
2895b843c749SSergey Zigachev 		dm->backlight_dev = NULL;
2896b843c749SSergey Zigachev 	}
2897b843c749SSergey Zigachev #endif
2898b843c749SSergey Zigachev 	drm_connector_unregister(connector);
2899b843c749SSergey Zigachev 	drm_connector_cleanup(connector);
2900b843c749SSergey Zigachev 	kfree(connector);
2901b843c749SSergey Zigachev }
2902b843c749SSergey Zigachev 
amdgpu_dm_connector_funcs_reset(struct drm_connector * connector)2903b843c749SSergey Zigachev void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector)
2904b843c749SSergey Zigachev {
2905b843c749SSergey Zigachev 	struct dm_connector_state *state =
2906b843c749SSergey Zigachev 		to_dm_connector_state(connector->state);
2907b843c749SSergey Zigachev 
2908b843c749SSergey Zigachev 	if (connector->state)
2909b843c749SSergey Zigachev 		__drm_atomic_helper_connector_destroy_state(connector->state);
2910b843c749SSergey Zigachev 
2911b843c749SSergey Zigachev 	kfree(state);
2912b843c749SSergey Zigachev 
2913b843c749SSergey Zigachev 	state = kzalloc(sizeof(*state), GFP_KERNEL);
2914b843c749SSergey Zigachev 
2915b843c749SSergey Zigachev 	if (state) {
2916b843c749SSergey Zigachev 		state->scaling = RMX_OFF;
2917b843c749SSergey Zigachev 		state->underscan_enable = false;
2918b843c749SSergey Zigachev 		state->underscan_hborder = 0;
2919b843c749SSergey Zigachev 		state->underscan_vborder = 0;
2920b843c749SSergey Zigachev 		state->max_bpc = 8;
2921b843c749SSergey Zigachev 
2922b843c749SSergey Zigachev 		__drm_atomic_helper_connector_reset(connector, &state->base);
2923b843c749SSergey Zigachev 	}
2924b843c749SSergey Zigachev }
2925b843c749SSergey Zigachev 
2926b843c749SSergey Zigachev struct drm_connector_state *
amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector * connector)2927b843c749SSergey Zigachev amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector)
2928b843c749SSergey Zigachev {
2929b843c749SSergey Zigachev 	struct dm_connector_state *state =
2930b843c749SSergey Zigachev 		to_dm_connector_state(connector->state);
2931b843c749SSergey Zigachev 
2932b843c749SSergey Zigachev 	struct dm_connector_state *new_state =
2933b843c749SSergey Zigachev 			kmemdup(state, sizeof(*state), GFP_KERNEL);
2934b843c749SSergey Zigachev 
2935b843c749SSergey Zigachev 	if (new_state) {
2936b843c749SSergey Zigachev 		__drm_atomic_helper_connector_duplicate_state(connector,
2937b843c749SSergey Zigachev 							      &new_state->base);
2938b843c749SSergey Zigachev 		new_state->max_bpc = state->max_bpc;
2939b843c749SSergey Zigachev 		return &new_state->base;
2940b843c749SSergey Zigachev 	}
2941b843c749SSergey Zigachev 
2942b843c749SSergey Zigachev 	return NULL;
2943b843c749SSergey Zigachev }
2944b843c749SSergey Zigachev 
2945b843c749SSergey Zigachev static const struct drm_connector_funcs amdgpu_dm_connector_funcs = {
2946b843c749SSergey Zigachev 	.reset = amdgpu_dm_connector_funcs_reset,
2947b843c749SSergey Zigachev 	.detect = amdgpu_dm_connector_detect,
2948b843c749SSergey Zigachev 	.fill_modes = drm_helper_probe_single_connector_modes,
2949b843c749SSergey Zigachev 	.destroy = amdgpu_dm_connector_destroy,
2950b843c749SSergey Zigachev 	.atomic_duplicate_state = amdgpu_dm_connector_atomic_duplicate_state,
2951b843c749SSergey Zigachev 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
2952b843c749SSergey Zigachev 	.atomic_set_property = amdgpu_dm_connector_atomic_set_property,
2953b843c749SSergey Zigachev 	.atomic_get_property = amdgpu_dm_connector_atomic_get_property
2954b843c749SSergey Zigachev };
2955b843c749SSergey Zigachev 
best_encoder(struct drm_connector * connector)2956b843c749SSergey Zigachev static struct drm_encoder *best_encoder(struct drm_connector *connector)
2957b843c749SSergey Zigachev {
2958b843c749SSergey Zigachev 	int enc_id = connector->encoder_ids[0];
2959b843c749SSergey Zigachev 	struct drm_mode_object *obj;
2960b843c749SSergey Zigachev 	struct drm_encoder *encoder;
2961b843c749SSergey Zigachev 
2962b843c749SSergey Zigachev 	DRM_DEBUG_DRIVER("Finding the best encoder\n");
2963b843c749SSergey Zigachev 
2964b843c749SSergey Zigachev 	/* pick the encoder ids */
2965b843c749SSergey Zigachev 	if (enc_id) {
2966b843c749SSergey Zigachev 		obj = drm_mode_object_find(connector->dev, NULL, enc_id, DRM_MODE_OBJECT_ENCODER);
2967b843c749SSergey Zigachev 		if (!obj) {
2968b843c749SSergey Zigachev 			DRM_ERROR("Couldn't find a matching encoder for our connector\n");
2969b843c749SSergey Zigachev 			return NULL;
2970b843c749SSergey Zigachev 		}
2971b843c749SSergey Zigachev 		encoder = obj_to_encoder(obj);
2972b843c749SSergey Zigachev 		return encoder;
2973b843c749SSergey Zigachev 	}
2974b843c749SSergey Zigachev 	DRM_ERROR("No encoder id\n");
2975b843c749SSergey Zigachev 	return NULL;
2976b843c749SSergey Zigachev }
2977b843c749SSergey Zigachev 
get_modes(struct drm_connector * connector)2978b843c749SSergey Zigachev static int get_modes(struct drm_connector *connector)
2979b843c749SSergey Zigachev {
2980b843c749SSergey Zigachev 	return amdgpu_dm_connector_get_modes(connector);
2981b843c749SSergey Zigachev }
2982b843c749SSergey Zigachev 
create_eml_sink(struct amdgpu_dm_connector * aconnector)2983b843c749SSergey Zigachev static void create_eml_sink(struct amdgpu_dm_connector *aconnector)
2984b843c749SSergey Zigachev {
2985b843c749SSergey Zigachev 	struct dc_sink_init_data init_params = {
2986b843c749SSergey Zigachev 			.link = aconnector->dc_link,
2987b843c749SSergey Zigachev 			.sink_signal = SIGNAL_TYPE_VIRTUAL
2988b843c749SSergey Zigachev 	};
2989b843c749SSergey Zigachev 	struct edid *edid;
2990b843c749SSergey Zigachev 
2991b843c749SSergey Zigachev 	if (!aconnector->base.edid_blob_ptr) {
2992b843c749SSergey Zigachev 		DRM_ERROR("No EDID firmware found on connector: %s ,forcing to OFF!\n",
2993b843c749SSergey Zigachev 				aconnector->base.name);
2994b843c749SSergey Zigachev 
2995b843c749SSergey Zigachev 		aconnector->base.force = DRM_FORCE_OFF;
2996b843c749SSergey Zigachev 		aconnector->base.override_edid = false;
2997b843c749SSergey Zigachev 		return;
2998b843c749SSergey Zigachev 	}
2999b843c749SSergey Zigachev 
3000b843c749SSergey Zigachev 	edid = (struct edid *) aconnector->base.edid_blob_ptr->data;
3001b843c749SSergey Zigachev 
3002b843c749SSergey Zigachev 	aconnector->edid = edid;
3003b843c749SSergey Zigachev 
3004b843c749SSergey Zigachev 	aconnector->dc_em_sink = dc_link_add_remote_sink(
3005b843c749SSergey Zigachev 		aconnector->dc_link,
3006b843c749SSergey Zigachev 		(uint8_t *)edid,
3007b843c749SSergey Zigachev 		(edid->extensions + 1) * EDID_LENGTH,
3008b843c749SSergey Zigachev 		&init_params);
3009b843c749SSergey Zigachev 
3010b843c749SSergey Zigachev 	if (aconnector->base.force == DRM_FORCE_ON)
3011b843c749SSergey Zigachev 		aconnector->dc_sink = aconnector->dc_link->local_sink ?
3012b843c749SSergey Zigachev 		aconnector->dc_link->local_sink :
3013b843c749SSergey Zigachev 		aconnector->dc_em_sink;
3014b843c749SSergey Zigachev }
3015b843c749SSergey Zigachev 
handle_edid_mgmt(struct amdgpu_dm_connector * aconnector)3016b843c749SSergey Zigachev static void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector)
3017b843c749SSergey Zigachev {
3018b843c749SSergey Zigachev 	struct dc_link *link = (struct dc_link *)aconnector->dc_link;
3019b843c749SSergey Zigachev 
3020b843c749SSergey Zigachev 	/* In case of headless boot with force on for DP managed connector
3021b843c749SSergey Zigachev 	 * Those settings have to be != 0 to get initial modeset
3022b843c749SSergey Zigachev 	 */
3023b843c749SSergey Zigachev 	if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT) {
3024b843c749SSergey Zigachev 		link->verified_link_cap.lane_count = LANE_COUNT_FOUR;
3025b843c749SSergey Zigachev 		link->verified_link_cap.link_rate = LINK_RATE_HIGH2;
3026b843c749SSergey Zigachev 	}
3027b843c749SSergey Zigachev 
3028b843c749SSergey Zigachev 
3029b843c749SSergey Zigachev 	aconnector->base.override_edid = true;
3030b843c749SSergey Zigachev 	create_eml_sink(aconnector);
3031b843c749SSergey Zigachev }
3032b843c749SSergey Zigachev 
amdgpu_dm_connector_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)3033b843c749SSergey Zigachev enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connector,
3034b843c749SSergey Zigachev 				   struct drm_display_mode *mode)
3035b843c749SSergey Zigachev {
3036b843c749SSergey Zigachev 	int result = MODE_ERROR;
3037b843c749SSergey Zigachev 	struct dc_sink *dc_sink;
3038b843c749SSergey Zigachev 	struct amdgpu_device *adev = connector->dev->dev_private;
3039b843c749SSergey Zigachev 	/* TODO: Unhardcode stream count */
3040b843c749SSergey Zigachev 	struct dc_stream_state *stream;
3041b843c749SSergey Zigachev 	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
3042b843c749SSergey Zigachev 	enum dc_status dc_result = DC_OK;
3043b843c749SSergey Zigachev 
3044b843c749SSergey Zigachev 	if ((mode->flags & DRM_MODE_FLAG_INTERLACE) ||
3045b843c749SSergey Zigachev 			(mode->flags & DRM_MODE_FLAG_DBLSCAN))
3046b843c749SSergey Zigachev 		return result;
3047b843c749SSergey Zigachev 
3048b843c749SSergey Zigachev 	/* Only run this the first time mode_valid is called to initilialize
3049b843c749SSergey Zigachev 	 * EDID mgmt
3050b843c749SSergey Zigachev 	 */
3051b843c749SSergey Zigachev 	if (aconnector->base.force != DRM_FORCE_UNSPECIFIED &&
3052b843c749SSergey Zigachev 		!aconnector->dc_em_sink)
3053b843c749SSergey Zigachev 		handle_edid_mgmt(aconnector);
3054b843c749SSergey Zigachev 
3055b843c749SSergey Zigachev 	dc_sink = to_amdgpu_dm_connector(connector)->dc_sink;
3056b843c749SSergey Zigachev 
3057b843c749SSergey Zigachev 	if (dc_sink == NULL) {
3058b843c749SSergey Zigachev 		DRM_ERROR("dc_sink is NULL!\n");
3059b843c749SSergey Zigachev 		goto fail;
3060b843c749SSergey Zigachev 	}
3061b843c749SSergey Zigachev 
3062b843c749SSergey Zigachev 	stream = create_stream_for_sink(aconnector, mode, NULL);
3063b843c749SSergey Zigachev 	if (stream == NULL) {
3064b843c749SSergey Zigachev 		DRM_ERROR("Failed to create stream for sink!\n");
3065b843c749SSergey Zigachev 		goto fail;
3066b843c749SSergey Zigachev 	}
3067b843c749SSergey Zigachev 
3068b843c749SSergey Zigachev 	dc_result = dc_validate_stream(adev->dm.dc, stream);
3069b843c749SSergey Zigachev 
3070b843c749SSergey Zigachev 	if (dc_result == DC_OK)
3071b843c749SSergey Zigachev 		result = MODE_OK;
3072b843c749SSergey Zigachev 	else
3073b843c749SSergey Zigachev 		DRM_DEBUG_KMS("Mode %dx%d (clk %d) failed DC validation with error %d\n",
3074b843c749SSergey Zigachev 			      mode->vdisplay,
3075b843c749SSergey Zigachev 			      mode->hdisplay,
3076b843c749SSergey Zigachev 			      mode->clock,
3077b843c749SSergey Zigachev 			      dc_result);
3078b843c749SSergey Zigachev 
3079b843c749SSergey Zigachev 	dc_stream_release(stream);
3080b843c749SSergey Zigachev 
3081b843c749SSergey Zigachev fail:
3082b843c749SSergey Zigachev 	/* TODO: error handling*/
3083b843c749SSergey Zigachev 	return result;
3084b843c749SSergey Zigachev }
3085b843c749SSergey Zigachev 
3086b843c749SSergey Zigachev static const struct drm_connector_helper_funcs
3087b843c749SSergey Zigachev amdgpu_dm_connector_helper_funcs = {
3088b843c749SSergey Zigachev 	/*
3089b843c749SSergey Zigachev 	 * If hotplug a second bigger display in FB Con mode, bigger resolution
3090b843c749SSergey Zigachev 	 * modes will be filtered by drm_mode_validate_size(), and those modes
3091b843c749SSergey Zigachev 	 * is missing after user start lightdm. So we need to renew modes list.
3092b843c749SSergey Zigachev 	 * in get_modes call back, not just return the modes count
3093b843c749SSergey Zigachev 	 */
3094b843c749SSergey Zigachev 	.get_modes = get_modes,
3095b843c749SSergey Zigachev 	.mode_valid = amdgpu_dm_connector_mode_valid,
3096b843c749SSergey Zigachev 	.best_encoder = best_encoder
3097b843c749SSergey Zigachev };
3098b843c749SSergey Zigachev 
dm_crtc_helper_disable(struct drm_crtc * crtc)3099b843c749SSergey Zigachev static void dm_crtc_helper_disable(struct drm_crtc *crtc)
3100b843c749SSergey Zigachev {
3101b843c749SSergey Zigachev }
3102b843c749SSergey Zigachev 
dm_crtc_helper_atomic_check(struct drm_crtc * crtc,struct drm_crtc_state * state)3103b843c749SSergey Zigachev static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
3104b843c749SSergey Zigachev 				       struct drm_crtc_state *state)
3105b843c749SSergey Zigachev {
3106b843c749SSergey Zigachev 	struct amdgpu_device *adev = crtc->dev->dev_private;
3107b843c749SSergey Zigachev 	struct dc *dc = adev->dm.dc;
3108b843c749SSergey Zigachev 	struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(state);
3109b843c749SSergey Zigachev 	int ret = -EINVAL;
3110b843c749SSergey Zigachev 
3111b843c749SSergey Zigachev 	if (unlikely(!dm_crtc_state->stream &&
3112b843c749SSergey Zigachev 		     modeset_required(state, NULL, dm_crtc_state->stream))) {
3113b843c749SSergey Zigachev 		WARN_ON(1);
3114b843c749SSergey Zigachev 		return ret;
3115b843c749SSergey Zigachev 	}
3116b843c749SSergey Zigachev 
3117b843c749SSergey Zigachev 	/* In some use cases, like reset, no stream  is attached */
3118b843c749SSergey Zigachev 	if (!dm_crtc_state->stream)
3119b843c749SSergey Zigachev 		return 0;
3120b843c749SSergey Zigachev 
3121b843c749SSergey Zigachev 	if (dc_validate_stream(dc, dm_crtc_state->stream) == DC_OK)
3122b843c749SSergey Zigachev 		return 0;
3123b843c749SSergey Zigachev 
3124b843c749SSergey Zigachev 	return ret;
3125b843c749SSergey Zigachev }
3126b843c749SSergey Zigachev 
dm_crtc_helper_mode_fixup(struct drm_crtc * crtc,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)3127b843c749SSergey Zigachev static bool dm_crtc_helper_mode_fixup(struct drm_crtc *crtc,
3128b843c749SSergey Zigachev 				      const struct drm_display_mode *mode,
3129b843c749SSergey Zigachev 				      struct drm_display_mode *adjusted_mode)
3130b843c749SSergey Zigachev {
3131b843c749SSergey Zigachev 	return true;
3132b843c749SSergey Zigachev }
3133b843c749SSergey Zigachev 
3134b843c749SSergey Zigachev static const struct drm_crtc_helper_funcs amdgpu_dm_crtc_helper_funcs = {
3135b843c749SSergey Zigachev 	.disable = dm_crtc_helper_disable,
3136b843c749SSergey Zigachev 	.atomic_check = dm_crtc_helper_atomic_check,
3137b843c749SSergey Zigachev 	.mode_fixup = dm_crtc_helper_mode_fixup
3138b843c749SSergey Zigachev };
3139b843c749SSergey Zigachev 
dm_encoder_helper_disable(struct drm_encoder * encoder)3140b843c749SSergey Zigachev static void dm_encoder_helper_disable(struct drm_encoder *encoder)
3141b843c749SSergey Zigachev {
3142b843c749SSergey Zigachev 
3143b843c749SSergey Zigachev }
3144b843c749SSergey Zigachev 
dm_encoder_helper_atomic_check(struct drm_encoder * encoder,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state)3145b843c749SSergey Zigachev static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
3146b843c749SSergey Zigachev 					  struct drm_crtc_state *crtc_state,
3147b843c749SSergey Zigachev 					  struct drm_connector_state *conn_state)
3148b843c749SSergey Zigachev {
3149b843c749SSergey Zigachev 	return 0;
3150b843c749SSergey Zigachev }
3151b843c749SSergey Zigachev 
3152b843c749SSergey Zigachev const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs = {
3153b843c749SSergey Zigachev 	.disable = dm_encoder_helper_disable,
3154b843c749SSergey Zigachev 	.atomic_check = dm_encoder_helper_atomic_check
3155b843c749SSergey Zigachev };
3156b843c749SSergey Zigachev 
dm_drm_plane_reset(struct drm_plane * plane)3157b843c749SSergey Zigachev static void dm_drm_plane_reset(struct drm_plane *plane)
3158b843c749SSergey Zigachev {
3159b843c749SSergey Zigachev 	struct dm_plane_state *amdgpu_state = NULL;
3160b843c749SSergey Zigachev 
3161b843c749SSergey Zigachev 	if (plane->state)
3162b843c749SSergey Zigachev 		plane->funcs->atomic_destroy_state(plane, plane->state);
3163b843c749SSergey Zigachev 
3164b843c749SSergey Zigachev 	amdgpu_state = kzalloc(sizeof(*amdgpu_state), GFP_KERNEL);
3165b843c749SSergey Zigachev 	WARN_ON(amdgpu_state == NULL);
3166b843c749SSergey Zigachev 
3167b843c749SSergey Zigachev 	if (amdgpu_state) {
3168b843c749SSergey Zigachev 		plane->state = &amdgpu_state->base;
3169b843c749SSergey Zigachev 		plane->state->plane = plane;
3170b843c749SSergey Zigachev 		plane->state->rotation = DRM_MODE_ROTATE_0;
3171b843c749SSergey Zigachev 	}
3172b843c749SSergey Zigachev }
3173b843c749SSergey Zigachev 
3174b843c749SSergey Zigachev static struct drm_plane_state *
dm_drm_plane_duplicate_state(struct drm_plane * plane)3175b843c749SSergey Zigachev dm_drm_plane_duplicate_state(struct drm_plane *plane)
3176b843c749SSergey Zigachev {
3177b843c749SSergey Zigachev 	struct dm_plane_state *dm_plane_state, *old_dm_plane_state;
3178b843c749SSergey Zigachev 
3179b843c749SSergey Zigachev 	old_dm_plane_state = to_dm_plane_state(plane->state);
3180b843c749SSergey Zigachev 	dm_plane_state = kzalloc(sizeof(*dm_plane_state), GFP_KERNEL);
3181b843c749SSergey Zigachev 	if (!dm_plane_state)
3182b843c749SSergey Zigachev 		return NULL;
3183b843c749SSergey Zigachev 
3184b843c749SSergey Zigachev 	__drm_atomic_helper_plane_duplicate_state(plane, &dm_plane_state->base);
3185b843c749SSergey Zigachev 
3186b843c749SSergey Zigachev 	if (old_dm_plane_state->dc_state) {
3187b843c749SSergey Zigachev 		dm_plane_state->dc_state = old_dm_plane_state->dc_state;
3188b843c749SSergey Zigachev 		dc_plane_state_retain(dm_plane_state->dc_state);
3189b843c749SSergey Zigachev 	}
3190b843c749SSergey Zigachev 
3191b843c749SSergey Zigachev 	return &dm_plane_state->base;
3192b843c749SSergey Zigachev }
3193b843c749SSergey Zigachev 
3194*78973132SSergey Zigachev static
dm_drm_plane_destroy_state(struct drm_plane * plane,struct drm_plane_state * state)3195b843c749SSergey Zigachev void dm_drm_plane_destroy_state(struct drm_plane *plane,
3196b843c749SSergey Zigachev 				struct drm_plane_state *state)
3197b843c749SSergey Zigachev {
3198b843c749SSergey Zigachev 	struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
3199b843c749SSergey Zigachev 
3200b843c749SSergey Zigachev 	if (dm_plane_state->dc_state)
3201b843c749SSergey Zigachev 		dc_plane_state_release(dm_plane_state->dc_state);
3202b843c749SSergey Zigachev 
3203b843c749SSergey Zigachev 	drm_atomic_helper_plane_destroy_state(plane, state);
3204b843c749SSergey Zigachev }
3205b843c749SSergey Zigachev 
3206b843c749SSergey Zigachev static const struct drm_plane_funcs dm_plane_funcs = {
3207b843c749SSergey Zigachev 	.update_plane	= drm_atomic_helper_update_plane,
3208b843c749SSergey Zigachev 	.disable_plane	= drm_atomic_helper_disable_plane,
3209b843c749SSergey Zigachev 	.destroy	= drm_primary_helper_destroy,
3210b843c749SSergey Zigachev 	.reset = dm_drm_plane_reset,
3211b843c749SSergey Zigachev 	.atomic_duplicate_state = dm_drm_plane_duplicate_state,
3212b843c749SSergey Zigachev 	.atomic_destroy_state = dm_drm_plane_destroy_state,
3213b843c749SSergey Zigachev };
3214b843c749SSergey Zigachev 
dm_plane_helper_prepare_fb(struct drm_plane * plane,struct drm_plane_state * new_state)3215b843c749SSergey Zigachev static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
3216b843c749SSergey Zigachev 				      struct drm_plane_state *new_state)
3217b843c749SSergey Zigachev {
3218b843c749SSergey Zigachev 	struct amdgpu_framebuffer *afb;
3219b843c749SSergey Zigachev 	struct drm_gem_object *obj;
3220b843c749SSergey Zigachev 	struct amdgpu_device *adev;
3221b843c749SSergey Zigachev 	struct amdgpu_bo *rbo;
3222b843c749SSergey Zigachev 	uint64_t chroma_addr = 0;
3223b843c749SSergey Zigachev 	struct dm_plane_state *dm_plane_state_new, *dm_plane_state_old;
3224b843c749SSergey Zigachev 	unsigned int awidth;
3225b843c749SSergey Zigachev 	uint32_t domain;
3226b843c749SSergey Zigachev 	int r;
3227b843c749SSergey Zigachev 
3228b843c749SSergey Zigachev 	dm_plane_state_old = to_dm_plane_state(plane->state);
3229b843c749SSergey Zigachev 	dm_plane_state_new = to_dm_plane_state(new_state);
3230b843c749SSergey Zigachev 
3231b843c749SSergey Zigachev 	if (!new_state->fb) {
3232b843c749SSergey Zigachev 		DRM_DEBUG_DRIVER("No FB bound\n");
3233b843c749SSergey Zigachev 		return 0;
3234b843c749SSergey Zigachev 	}
3235b843c749SSergey Zigachev 
3236b843c749SSergey Zigachev 	afb = to_amdgpu_framebuffer(new_state->fb);
3237b843c749SSergey Zigachev 	obj = new_state->fb->obj[0];
3238b843c749SSergey Zigachev 	rbo = gem_to_amdgpu_bo(obj);
3239b843c749SSergey Zigachev 	adev = amdgpu_ttm_adev(rbo->tbo.bdev);
3240b843c749SSergey Zigachev 	r = amdgpu_bo_reserve(rbo, false);
3241b843c749SSergey Zigachev 	if (unlikely(r != 0))
3242b843c749SSergey Zigachev 		return r;
3243b843c749SSergey Zigachev 
3244b843c749SSergey Zigachev 	if (plane->type != DRM_PLANE_TYPE_CURSOR)
3245b843c749SSergey Zigachev 		domain = amdgpu_display_supported_domains(adev);
3246b843c749SSergey Zigachev 	else
3247b843c749SSergey Zigachev 		domain = AMDGPU_GEM_DOMAIN_VRAM;
3248b843c749SSergey Zigachev 
3249b843c749SSergey Zigachev 	r = amdgpu_bo_pin(rbo, domain);
3250b843c749SSergey Zigachev 	if (unlikely(r != 0)) {
3251b843c749SSergey Zigachev 		if (r != -ERESTARTSYS)
3252b843c749SSergey Zigachev 			DRM_ERROR("Failed to pin framebuffer with error %d\n", r);
3253b843c749SSergey Zigachev 		amdgpu_bo_unreserve(rbo);
3254b843c749SSergey Zigachev 		return r;
3255b843c749SSergey Zigachev 	}
3256b843c749SSergey Zigachev 
3257b843c749SSergey Zigachev 	r = amdgpu_ttm_alloc_gart(&rbo->tbo);
3258b843c749SSergey Zigachev 	if (unlikely(r != 0)) {
3259b843c749SSergey Zigachev 		amdgpu_bo_unpin(rbo);
3260b843c749SSergey Zigachev 		amdgpu_bo_unreserve(rbo);
3261b843c749SSergey Zigachev 		DRM_ERROR("%p bind failed\n", rbo);
3262b843c749SSergey Zigachev 		return r;
3263b843c749SSergey Zigachev 	}
3264b843c749SSergey Zigachev 	amdgpu_bo_unreserve(rbo);
3265b843c749SSergey Zigachev 
3266b843c749SSergey Zigachev 	afb->address = amdgpu_bo_gpu_offset(rbo);
3267b843c749SSergey Zigachev 
3268b843c749SSergey Zigachev 	amdgpu_bo_ref(rbo);
3269b843c749SSergey Zigachev 
3270b843c749SSergey Zigachev 	if (dm_plane_state_new->dc_state &&
3271b843c749SSergey Zigachev 			dm_plane_state_old->dc_state != dm_plane_state_new->dc_state) {
3272b843c749SSergey Zigachev 		struct dc_plane_state *plane_state = dm_plane_state_new->dc_state;
3273b843c749SSergey Zigachev 
3274b843c749SSergey Zigachev 		if (plane_state->format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) {
3275b843c749SSergey Zigachev 			plane_state->address.grph.addr.low_part = lower_32_bits(afb->address);
3276b843c749SSergey Zigachev 			plane_state->address.grph.addr.high_part = upper_32_bits(afb->address);
3277b843c749SSergey Zigachev 		} else {
3278b843c749SSergey Zigachev 			awidth = ALIGN(new_state->fb->width, 64);
3279b843c749SSergey Zigachev 			plane_state->address.type = PLN_ADDR_TYPE_VIDEO_PROGRESSIVE;
3280b843c749SSergey Zigachev 			plane_state->address.video_progressive.luma_addr.low_part
3281b843c749SSergey Zigachev 							= lower_32_bits(afb->address);
3282b843c749SSergey Zigachev 			plane_state->address.video_progressive.luma_addr.high_part
3283b843c749SSergey Zigachev 							= upper_32_bits(afb->address);
3284b843c749SSergey Zigachev 			chroma_addr = afb->address + (u64)awidth * new_state->fb->height;
3285b843c749SSergey Zigachev 			plane_state->address.video_progressive.chroma_addr.low_part
3286b843c749SSergey Zigachev 							= lower_32_bits(chroma_addr);
3287b843c749SSergey Zigachev 			plane_state->address.video_progressive.chroma_addr.high_part
3288b843c749SSergey Zigachev 							= upper_32_bits(chroma_addr);
3289b843c749SSergey Zigachev 		}
3290b843c749SSergey Zigachev 	}
3291b843c749SSergey Zigachev 
3292b843c749SSergey Zigachev 	return 0;
3293b843c749SSergey Zigachev }
3294b843c749SSergey Zigachev 
dm_plane_helper_cleanup_fb(struct drm_plane * plane,struct drm_plane_state * old_state)3295b843c749SSergey Zigachev static void dm_plane_helper_cleanup_fb(struct drm_plane *plane,
3296b843c749SSergey Zigachev 				       struct drm_plane_state *old_state)
3297b843c749SSergey Zigachev {
3298b843c749SSergey Zigachev 	struct amdgpu_bo *rbo;
3299b843c749SSergey Zigachev 	int r;
3300b843c749SSergey Zigachev 
3301b843c749SSergey Zigachev 	if (!old_state->fb)
3302b843c749SSergey Zigachev 		return;
3303b843c749SSergey Zigachev 
3304b843c749SSergey Zigachev 	rbo = gem_to_amdgpu_bo(old_state->fb->obj[0]);
3305b843c749SSergey Zigachev 	r = amdgpu_bo_reserve(rbo, false);
3306b843c749SSergey Zigachev 	if (unlikely(r)) {
3307b843c749SSergey Zigachev 		DRM_ERROR("failed to reserve rbo before unpin\n");
3308b843c749SSergey Zigachev 		return;
3309b843c749SSergey Zigachev 	}
3310b843c749SSergey Zigachev 
3311b843c749SSergey Zigachev 	amdgpu_bo_unpin(rbo);
3312b843c749SSergey Zigachev 	amdgpu_bo_unreserve(rbo);
3313b843c749SSergey Zigachev 	amdgpu_bo_unref(&rbo);
3314b843c749SSergey Zigachev }
3315b843c749SSergey Zigachev 
dm_plane_atomic_check(struct drm_plane * plane,struct drm_plane_state * state)3316b843c749SSergey Zigachev static int dm_plane_atomic_check(struct drm_plane *plane,
3317b843c749SSergey Zigachev 				 struct drm_plane_state *state)
3318b843c749SSergey Zigachev {
3319b843c749SSergey Zigachev 	struct amdgpu_device *adev = plane->dev->dev_private;
3320b843c749SSergey Zigachev 	struct dc *dc = adev->dm.dc;
3321b843c749SSergey Zigachev 	struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
3322b843c749SSergey Zigachev 
3323b843c749SSergey Zigachev 	if (!dm_plane_state->dc_state)
3324b843c749SSergey Zigachev 		return 0;
3325b843c749SSergey Zigachev 
3326b843c749SSergey Zigachev 	if (!fill_rects_from_plane_state(state, dm_plane_state->dc_state))
3327b843c749SSergey Zigachev 		return -EINVAL;
3328b843c749SSergey Zigachev 
3329b843c749SSergey Zigachev 	if (dc_validate_plane(dc, dm_plane_state->dc_state) == DC_OK)
3330b843c749SSergey Zigachev 		return 0;
3331b843c749SSergey Zigachev 
3332b843c749SSergey Zigachev 	return -EINVAL;
3333b843c749SSergey Zigachev }
3334b843c749SSergey Zigachev 
3335b843c749SSergey Zigachev static const struct drm_plane_helper_funcs dm_plane_helper_funcs = {
3336b843c749SSergey Zigachev 	.prepare_fb = dm_plane_helper_prepare_fb,
3337b843c749SSergey Zigachev 	.cleanup_fb = dm_plane_helper_cleanup_fb,
3338b843c749SSergey Zigachev 	.atomic_check = dm_plane_atomic_check,
3339b843c749SSergey Zigachev };
3340b843c749SSergey Zigachev 
3341b843c749SSergey Zigachev /*
3342b843c749SSergey Zigachev  * TODO: these are currently initialized to rgb formats only.
3343b843c749SSergey Zigachev  * For future use cases we should either initialize them dynamically based on
3344b843c749SSergey Zigachev  * plane capabilities, or initialize this array to all formats, so internal drm
3345b843c749SSergey Zigachev  * check will succeed, and let DC to implement proper check
3346b843c749SSergey Zigachev  */
3347b843c749SSergey Zigachev static const uint32_t rgb_formats[] = {
3348b843c749SSergey Zigachev 	DRM_FORMAT_RGB888,
3349b843c749SSergey Zigachev 	DRM_FORMAT_XRGB8888,
3350b843c749SSergey Zigachev 	DRM_FORMAT_ARGB8888,
3351b843c749SSergey Zigachev 	DRM_FORMAT_RGBA8888,
3352b843c749SSergey Zigachev 	DRM_FORMAT_XRGB2101010,
3353b843c749SSergey Zigachev 	DRM_FORMAT_XBGR2101010,
3354b843c749SSergey Zigachev 	DRM_FORMAT_ARGB2101010,
3355b843c749SSergey Zigachev 	DRM_FORMAT_ABGR2101010,
3356b843c749SSergey Zigachev };
3357b843c749SSergey Zigachev 
3358b843c749SSergey Zigachev static const uint32_t yuv_formats[] = {
3359b843c749SSergey Zigachev 	DRM_FORMAT_NV12,
3360b843c749SSergey Zigachev 	DRM_FORMAT_NV21,
3361b843c749SSergey Zigachev };
3362b843c749SSergey Zigachev 
3363b843c749SSergey Zigachev static const u32 cursor_formats[] = {
3364b843c749SSergey Zigachev 	DRM_FORMAT_ARGB8888
3365b843c749SSergey Zigachev };
3366b843c749SSergey Zigachev 
amdgpu_dm_plane_init(struct amdgpu_display_manager * dm,struct amdgpu_plane * aplane,unsigned long possible_crtcs)3367b843c749SSergey Zigachev static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
3368b843c749SSergey Zigachev 				struct amdgpu_plane *aplane,
3369b843c749SSergey Zigachev 				unsigned long possible_crtcs)
3370b843c749SSergey Zigachev {
3371b843c749SSergey Zigachev 	int res = -EPERM;
3372b843c749SSergey Zigachev 
3373b843c749SSergey Zigachev 	switch (aplane->base.type) {
3374b843c749SSergey Zigachev 	case DRM_PLANE_TYPE_PRIMARY:
3375b843c749SSergey Zigachev 		res = drm_universal_plane_init(
3376b843c749SSergey Zigachev 				dm->adev->ddev,
3377b843c749SSergey Zigachev 				&aplane->base,
3378b843c749SSergey Zigachev 				possible_crtcs,
3379b843c749SSergey Zigachev 				&dm_plane_funcs,
3380b843c749SSergey Zigachev 				rgb_formats,
3381b843c749SSergey Zigachev 				ARRAY_SIZE(rgb_formats),
3382b843c749SSergey Zigachev 				NULL, aplane->base.type, NULL);
3383b843c749SSergey Zigachev 		break;
3384b843c749SSergey Zigachev 	case DRM_PLANE_TYPE_OVERLAY:
3385b843c749SSergey Zigachev 		res = drm_universal_plane_init(
3386b843c749SSergey Zigachev 				dm->adev->ddev,
3387b843c749SSergey Zigachev 				&aplane->base,
3388b843c749SSergey Zigachev 				possible_crtcs,
3389b843c749SSergey Zigachev 				&dm_plane_funcs,
3390b843c749SSergey Zigachev 				yuv_formats,
3391b843c749SSergey Zigachev 				ARRAY_SIZE(yuv_formats),
3392b843c749SSergey Zigachev 				NULL, aplane->base.type, NULL);
3393b843c749SSergey Zigachev 		break;
3394b843c749SSergey Zigachev 	case DRM_PLANE_TYPE_CURSOR:
3395b843c749SSergey Zigachev 		res = drm_universal_plane_init(
3396b843c749SSergey Zigachev 				dm->adev->ddev,
3397b843c749SSergey Zigachev 				&aplane->base,
3398b843c749SSergey Zigachev 				possible_crtcs,
3399b843c749SSergey Zigachev 				&dm_plane_funcs,
3400b843c749SSergey Zigachev 				cursor_formats,
3401b843c749SSergey Zigachev 				ARRAY_SIZE(cursor_formats),
3402b843c749SSergey Zigachev 				NULL, aplane->base.type, NULL);
3403b843c749SSergey Zigachev 		break;
3404b843c749SSergey Zigachev 	}
3405b843c749SSergey Zigachev 
3406b843c749SSergey Zigachev 	drm_plane_helper_add(&aplane->base, &dm_plane_helper_funcs);
3407b843c749SSergey Zigachev 
3408b843c749SSergey Zigachev 	/* Create (reset) the plane state */
3409b843c749SSergey Zigachev 	if (aplane->base.funcs->reset)
3410b843c749SSergey Zigachev 		aplane->base.funcs->reset(&aplane->base);
3411b843c749SSergey Zigachev 
3412b843c749SSergey Zigachev 
3413b843c749SSergey Zigachev 	return res;
3414b843c749SSergey Zigachev }
3415b843c749SSergey Zigachev 
amdgpu_dm_crtc_init(struct amdgpu_display_manager * dm,struct drm_plane * plane,uint32_t crtc_index)3416b843c749SSergey Zigachev static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
3417b843c749SSergey Zigachev 			       struct drm_plane *plane,
3418b843c749SSergey Zigachev 			       uint32_t crtc_index)
3419b843c749SSergey Zigachev {
3420b843c749SSergey Zigachev 	struct amdgpu_crtc *acrtc = NULL;
3421b843c749SSergey Zigachev 	struct amdgpu_plane *cursor_plane;
3422b843c749SSergey Zigachev 
3423b843c749SSergey Zigachev 	int res = -ENOMEM;
3424b843c749SSergey Zigachev 
3425b843c749SSergey Zigachev 	cursor_plane = kzalloc(sizeof(*cursor_plane), GFP_KERNEL);
3426b843c749SSergey Zigachev 	if (!cursor_plane)
3427b843c749SSergey Zigachev 		goto fail;
3428b843c749SSergey Zigachev 
3429b843c749SSergey Zigachev 	cursor_plane->base.type = DRM_PLANE_TYPE_CURSOR;
3430b843c749SSergey Zigachev 	res = amdgpu_dm_plane_init(dm, cursor_plane, 0);
3431b843c749SSergey Zigachev 
3432b843c749SSergey Zigachev 	acrtc = kzalloc(sizeof(struct amdgpu_crtc), GFP_KERNEL);
3433b843c749SSergey Zigachev 	if (!acrtc)
3434b843c749SSergey Zigachev 		goto fail;
3435b843c749SSergey Zigachev 
3436b843c749SSergey Zigachev 	res = drm_crtc_init_with_planes(
3437b843c749SSergey Zigachev 			dm->ddev,
3438b843c749SSergey Zigachev 			&acrtc->base,
3439b843c749SSergey Zigachev 			plane,
3440b843c749SSergey Zigachev 			&cursor_plane->base,
3441b843c749SSergey Zigachev 			&amdgpu_dm_crtc_funcs, NULL);
3442b843c749SSergey Zigachev 
3443b843c749SSergey Zigachev 	if (res)
3444b843c749SSergey Zigachev 		goto fail;
3445b843c749SSergey Zigachev 
3446b843c749SSergey Zigachev 	drm_crtc_helper_add(&acrtc->base, &amdgpu_dm_crtc_helper_funcs);
3447b843c749SSergey Zigachev 
3448b843c749SSergey Zigachev 	/* Create (reset) the plane state */
3449b843c749SSergey Zigachev 	if (acrtc->base.funcs->reset)
3450b843c749SSergey Zigachev 		acrtc->base.funcs->reset(&acrtc->base);
3451b843c749SSergey Zigachev 
3452b843c749SSergey Zigachev 	acrtc->max_cursor_width = dm->adev->dm.dc->caps.max_cursor_size;
3453b843c749SSergey Zigachev 	acrtc->max_cursor_height = dm->adev->dm.dc->caps.max_cursor_size;
3454b843c749SSergey Zigachev 
3455b843c749SSergey Zigachev 	acrtc->crtc_id = crtc_index;
3456b843c749SSergey Zigachev 	acrtc->base.enabled = false;
3457b843c749SSergey Zigachev 
3458b843c749SSergey Zigachev 	dm->adev->mode_info.crtcs[crtc_index] = acrtc;
3459b843c749SSergey Zigachev 	drm_crtc_enable_color_mgmt(&acrtc->base, MAX_COLOR_LUT_ENTRIES,
3460b843c749SSergey Zigachev 				   true, MAX_COLOR_LUT_ENTRIES);
3461b843c749SSergey Zigachev 	drm_mode_crtc_set_gamma_size(&acrtc->base, MAX_COLOR_LEGACY_LUT_ENTRIES);
3462b843c749SSergey Zigachev 
3463b843c749SSergey Zigachev 	return 0;
3464b843c749SSergey Zigachev 
3465b843c749SSergey Zigachev fail:
3466b843c749SSergey Zigachev 	kfree(acrtc);
3467b843c749SSergey Zigachev 	kfree(cursor_plane);
3468b843c749SSergey Zigachev 	return res;
3469b843c749SSergey Zigachev }
3470b843c749SSergey Zigachev 
3471b843c749SSergey Zigachev 
to_drm_connector_type(enum signal_type st)3472b843c749SSergey Zigachev static int to_drm_connector_type(enum signal_type st)
3473b843c749SSergey Zigachev {
3474b843c749SSergey Zigachev 	switch (st) {
3475b843c749SSergey Zigachev 	case SIGNAL_TYPE_HDMI_TYPE_A:
3476b843c749SSergey Zigachev 		return DRM_MODE_CONNECTOR_HDMIA;
3477b843c749SSergey Zigachev 	case SIGNAL_TYPE_EDP:
3478b843c749SSergey Zigachev 		return DRM_MODE_CONNECTOR_eDP;
3479b843c749SSergey Zigachev 	case SIGNAL_TYPE_RGB:
3480b843c749SSergey Zigachev 		return DRM_MODE_CONNECTOR_VGA;
3481b843c749SSergey Zigachev 	case SIGNAL_TYPE_DISPLAY_PORT:
3482b843c749SSergey Zigachev 	case SIGNAL_TYPE_DISPLAY_PORT_MST:
3483b843c749SSergey Zigachev 		return DRM_MODE_CONNECTOR_DisplayPort;
3484b843c749SSergey Zigachev 	case SIGNAL_TYPE_DVI_DUAL_LINK:
3485b843c749SSergey Zigachev 	case SIGNAL_TYPE_DVI_SINGLE_LINK:
3486b843c749SSergey Zigachev 		return DRM_MODE_CONNECTOR_DVID;
3487b843c749SSergey Zigachev 	case SIGNAL_TYPE_VIRTUAL:
3488b843c749SSergey Zigachev 		return DRM_MODE_CONNECTOR_VIRTUAL;
3489b843c749SSergey Zigachev 
3490b843c749SSergey Zigachev 	default:
3491b843c749SSergey Zigachev 		return DRM_MODE_CONNECTOR_Unknown;
3492b843c749SSergey Zigachev 	}
3493b843c749SSergey Zigachev }
3494b843c749SSergey Zigachev 
amdgpu_dm_get_native_mode(struct drm_connector * connector)3495b843c749SSergey Zigachev static void amdgpu_dm_get_native_mode(struct drm_connector *connector)
3496b843c749SSergey Zigachev {
3497b843c749SSergey Zigachev 	const struct drm_connector_helper_funcs *helper =
3498b843c749SSergey Zigachev 		connector->helper_private;
3499b843c749SSergey Zigachev 	struct drm_encoder *encoder;
3500b843c749SSergey Zigachev 	struct amdgpu_encoder *amdgpu_encoder;
3501b843c749SSergey Zigachev 
3502b843c749SSergey Zigachev 	encoder = helper->best_encoder(connector);
3503b843c749SSergey Zigachev 
3504b843c749SSergey Zigachev 	if (encoder == NULL)
3505b843c749SSergey Zigachev 		return;
3506b843c749SSergey Zigachev 
3507b843c749SSergey Zigachev 	amdgpu_encoder = to_amdgpu_encoder(encoder);
3508b843c749SSergey Zigachev 
3509b843c749SSergey Zigachev 	amdgpu_encoder->native_mode.clock = 0;
3510b843c749SSergey Zigachev 
3511b843c749SSergey Zigachev 	if (!list_empty(&connector->probed_modes)) {
3512b843c749SSergey Zigachev 		struct drm_display_mode *preferred_mode = NULL;
3513b843c749SSergey Zigachev 
3514b843c749SSergey Zigachev 		list_for_each_entry(preferred_mode,
3515b843c749SSergey Zigachev 				    &connector->probed_modes,
3516b843c749SSergey Zigachev 				    head) {
3517b843c749SSergey Zigachev 			if (preferred_mode->type & DRM_MODE_TYPE_PREFERRED)
3518b843c749SSergey Zigachev 				amdgpu_encoder->native_mode = *preferred_mode;
3519b843c749SSergey Zigachev 
3520b843c749SSergey Zigachev 			break;
3521b843c749SSergey Zigachev 		}
3522b843c749SSergey Zigachev 
3523b843c749SSergey Zigachev 	}
3524b843c749SSergey Zigachev }
3525b843c749SSergey Zigachev 
3526b843c749SSergey Zigachev static struct drm_display_mode *
amdgpu_dm_create_common_mode(struct drm_encoder * encoder,char * name,int hdisplay,int vdisplay)3527b843c749SSergey Zigachev amdgpu_dm_create_common_mode(struct drm_encoder *encoder,
3528b843c749SSergey Zigachev 			     char *name,
3529b843c749SSergey Zigachev 			     int hdisplay, int vdisplay)
3530b843c749SSergey Zigachev {
3531b843c749SSergey Zigachev 	struct drm_device *dev = encoder->dev;
3532b843c749SSergey Zigachev 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
3533b843c749SSergey Zigachev 	struct drm_display_mode *mode = NULL;
3534b843c749SSergey Zigachev 	struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
3535b843c749SSergey Zigachev 
3536b843c749SSergey Zigachev 	mode = drm_mode_duplicate(dev, native_mode);
3537b843c749SSergey Zigachev 
3538b843c749SSergey Zigachev 	if (mode == NULL)
3539b843c749SSergey Zigachev 		return NULL;
3540b843c749SSergey Zigachev 
3541b843c749SSergey Zigachev 	mode->hdisplay = hdisplay;
3542b843c749SSergey Zigachev 	mode->vdisplay = vdisplay;
3543b843c749SSergey Zigachev 	mode->type &= ~DRM_MODE_TYPE_PREFERRED;
3544b843c749SSergey Zigachev 	strncpy(mode->name, name, DRM_DISPLAY_MODE_LEN);
3545b843c749SSergey Zigachev 
3546b843c749SSergey Zigachev 	return mode;
3547b843c749SSergey Zigachev 
3548b843c749SSergey Zigachev }
3549b843c749SSergey Zigachev 
amdgpu_dm_connector_add_common_modes(struct drm_encoder * encoder,struct drm_connector * connector)3550b843c749SSergey Zigachev static void amdgpu_dm_connector_add_common_modes(struct drm_encoder *encoder,
3551b843c749SSergey Zigachev 						 struct drm_connector *connector)
3552b843c749SSergey Zigachev {
3553b843c749SSergey Zigachev 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
3554b843c749SSergey Zigachev 	struct drm_display_mode *mode = NULL;
3555b843c749SSergey Zigachev 	struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
3556b843c749SSergey Zigachev 	struct amdgpu_dm_connector *amdgpu_dm_connector =
3557b843c749SSergey Zigachev 				to_amdgpu_dm_connector(connector);
3558b843c749SSergey Zigachev 	int i;
3559b843c749SSergey Zigachev 	int n;
3560b843c749SSergey Zigachev 	struct mode_size {
3561b843c749SSergey Zigachev 		char name[DRM_DISPLAY_MODE_LEN];
3562b843c749SSergey Zigachev 		int w;
3563b843c749SSergey Zigachev 		int h;
3564b843c749SSergey Zigachev 	} common_modes[] = {
3565b843c749SSergey Zigachev 		{  "640x480",  640,  480},
3566b843c749SSergey Zigachev 		{  "800x600",  800,  600},
3567b843c749SSergey Zigachev 		{ "1024x768", 1024,  768},
3568b843c749SSergey Zigachev 		{ "1280x720", 1280,  720},
3569b843c749SSergey Zigachev 		{ "1280x800", 1280,  800},
3570b843c749SSergey Zigachev 		{"1280x1024", 1280, 1024},
3571b843c749SSergey Zigachev 		{ "1440x900", 1440,  900},
3572b843c749SSergey Zigachev 		{"1680x1050", 1680, 1050},
3573b843c749SSergey Zigachev 		{"1600x1200", 1600, 1200},
3574b843c749SSergey Zigachev 		{"1920x1080", 1920, 1080},
3575b843c749SSergey Zigachev 		{"1920x1200", 1920, 1200}
3576b843c749SSergey Zigachev 	};
3577b843c749SSergey Zigachev 
3578b843c749SSergey Zigachev 	n = ARRAY_SIZE(common_modes);
3579b843c749SSergey Zigachev 
3580b843c749SSergey Zigachev 	for (i = 0; i < n; i++) {
3581b843c749SSergey Zigachev 		struct drm_display_mode *curmode = NULL;
3582b843c749SSergey Zigachev 		bool mode_existed = false;
3583b843c749SSergey Zigachev 
3584b843c749SSergey Zigachev 		if (common_modes[i].w > native_mode->hdisplay ||
3585b843c749SSergey Zigachev 		    common_modes[i].h > native_mode->vdisplay ||
3586b843c749SSergey Zigachev 		   (common_modes[i].w == native_mode->hdisplay &&
3587b843c749SSergey Zigachev 		    common_modes[i].h == native_mode->vdisplay))
3588b843c749SSergey Zigachev 			continue;
3589b843c749SSergey Zigachev 
3590b843c749SSergey Zigachev 		list_for_each_entry(curmode, &connector->probed_modes, head) {
3591b843c749SSergey Zigachev 			if (common_modes[i].w == curmode->hdisplay &&
3592b843c749SSergey Zigachev 			    common_modes[i].h == curmode->vdisplay) {
3593b843c749SSergey Zigachev 				mode_existed = true;
3594b843c749SSergey Zigachev 				break;
3595b843c749SSergey Zigachev 			}
3596b843c749SSergey Zigachev 		}
3597b843c749SSergey Zigachev 
3598b843c749SSergey Zigachev 		if (mode_existed)
3599b843c749SSergey Zigachev 			continue;
3600b843c749SSergey Zigachev 
3601b843c749SSergey Zigachev 		mode = amdgpu_dm_create_common_mode(encoder,
3602b843c749SSergey Zigachev 				common_modes[i].name, common_modes[i].w,
3603b843c749SSergey Zigachev 				common_modes[i].h);
3604b843c749SSergey Zigachev 		drm_mode_probed_add(connector, mode);
3605b843c749SSergey Zigachev 		amdgpu_dm_connector->num_modes++;
3606b843c749SSergey Zigachev 	}
3607b843c749SSergey Zigachev }
3608b843c749SSergey Zigachev 
amdgpu_dm_connector_ddc_get_modes(struct drm_connector * connector,struct edid * edid)3609b843c749SSergey Zigachev static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector,
3610b843c749SSergey Zigachev 					      struct edid *edid)
3611b843c749SSergey Zigachev {
3612b843c749SSergey Zigachev 	struct amdgpu_dm_connector *amdgpu_dm_connector =
3613b843c749SSergey Zigachev 			to_amdgpu_dm_connector(connector);
3614b843c749SSergey Zigachev 
3615b843c749SSergey Zigachev 	if (edid) {
3616b843c749SSergey Zigachev 		/* empty probed_modes */
3617b843c749SSergey Zigachev 		INIT_LIST_HEAD(&connector->probed_modes);
3618b843c749SSergey Zigachev 		amdgpu_dm_connector->num_modes =
3619b843c749SSergey Zigachev 				drm_add_edid_modes(connector, edid);
3620b843c749SSergey Zigachev 
3621b843c749SSergey Zigachev 		amdgpu_dm_get_native_mode(connector);
3622b843c749SSergey Zigachev 	} else {
3623b843c749SSergey Zigachev 		amdgpu_dm_connector->num_modes = 0;
3624b843c749SSergey Zigachev 	}
3625b843c749SSergey Zigachev }
3626b843c749SSergey Zigachev 
amdgpu_dm_connector_get_modes(struct drm_connector * connector)3627b843c749SSergey Zigachev static int amdgpu_dm_connector_get_modes(struct drm_connector *connector)
3628b843c749SSergey Zigachev {
3629b843c749SSergey Zigachev 	const struct drm_connector_helper_funcs *helper =
3630b843c749SSergey Zigachev 			connector->helper_private;
3631b843c749SSergey Zigachev 	struct amdgpu_dm_connector *amdgpu_dm_connector =
3632b843c749SSergey Zigachev 			to_amdgpu_dm_connector(connector);
3633b843c749SSergey Zigachev 	struct drm_encoder *encoder;
3634b843c749SSergey Zigachev 	struct edid *edid = amdgpu_dm_connector->edid;
3635b843c749SSergey Zigachev 
3636b843c749SSergey Zigachev 	encoder = helper->best_encoder(connector);
3637b843c749SSergey Zigachev 
3638b843c749SSergey Zigachev 	if (!edid || !drm_edid_is_valid(edid)) {
3639b843c749SSergey Zigachev 		drm_add_modes_noedid(connector, 640, 480);
3640b843c749SSergey Zigachev 	} else {
3641b843c749SSergey Zigachev 		amdgpu_dm_connector_ddc_get_modes(connector, edid);
3642b843c749SSergey Zigachev 		amdgpu_dm_connector_add_common_modes(encoder, connector);
3643b843c749SSergey Zigachev 	}
3644b843c749SSergey Zigachev 	amdgpu_dm_fbc_init(connector);
3645b843c749SSergey Zigachev 
3646b843c749SSergey Zigachev 	return amdgpu_dm_connector->num_modes;
3647b843c749SSergey Zigachev }
3648b843c749SSergey Zigachev 
amdgpu_dm_connector_init_helper(struct amdgpu_display_manager * dm,struct amdgpu_dm_connector * aconnector,int connector_type,struct dc_link * link,int link_index)3649b843c749SSergey Zigachev void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
3650b843c749SSergey Zigachev 				     struct amdgpu_dm_connector *aconnector,
3651b843c749SSergey Zigachev 				     int connector_type,
3652b843c749SSergey Zigachev 				     struct dc_link *link,
3653b843c749SSergey Zigachev 				     int link_index)
3654b843c749SSergey Zigachev {
3655b843c749SSergey Zigachev 	struct amdgpu_device *adev = dm->ddev->dev_private;
3656b843c749SSergey Zigachev 
3657b843c749SSergey Zigachev 	/*
3658b843c749SSergey Zigachev 	 * Some of the properties below require access to state, like bpc.
3659b843c749SSergey Zigachev 	 * Allocate some default initial connector state with our reset helper.
3660b843c749SSergey Zigachev 	 */
3661b843c749SSergey Zigachev 	if (aconnector->base.funcs->reset)
3662b843c749SSergey Zigachev 		aconnector->base.funcs->reset(&aconnector->base);
3663b843c749SSergey Zigachev 
3664b843c749SSergey Zigachev 	aconnector->connector_id = link_index;
3665b843c749SSergey Zigachev 	aconnector->dc_link = link;
3666b843c749SSergey Zigachev 	aconnector->base.interlace_allowed = false;
3667b843c749SSergey Zigachev 	aconnector->base.doublescan_allowed = false;
3668b843c749SSergey Zigachev 	aconnector->base.stereo_allowed = false;
3669b843c749SSergey Zigachev 	aconnector->base.dpms = DRM_MODE_DPMS_OFF;
3670b843c749SSergey Zigachev 	aconnector->hpd.hpd = AMDGPU_HPD_NONE; /* not used */
3671*78973132SSergey Zigachev 	lockinit(&aconnector->hpd_lock, "agdchpdl", 0, LK_CANRECURSE);
3672b843c749SSergey Zigachev 
3673b843c749SSergey Zigachev 	/* configure support HPD hot plug connector_>polled default value is 0
3674b843c749SSergey Zigachev 	 * which means HPD hot plug not supported
3675b843c749SSergey Zigachev 	 */
3676b843c749SSergey Zigachev 	switch (connector_type) {
3677b843c749SSergey Zigachev 	case DRM_MODE_CONNECTOR_HDMIA:
3678b843c749SSergey Zigachev 		aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
3679b843c749SSergey Zigachev 		aconnector->base.ycbcr_420_allowed =
3680b843c749SSergey Zigachev 			link->link_enc->features.ycbcr420_supported ? true : false;
3681b843c749SSergey Zigachev 		break;
3682b843c749SSergey Zigachev 	case DRM_MODE_CONNECTOR_DisplayPort:
3683b843c749SSergey Zigachev 		aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
3684b843c749SSergey Zigachev 		aconnector->base.ycbcr_420_allowed =
3685b843c749SSergey Zigachev 			link->link_enc->features.ycbcr420_supported ? true : false;
3686b843c749SSergey Zigachev 		break;
3687b843c749SSergey Zigachev 	case DRM_MODE_CONNECTOR_DVID:
3688b843c749SSergey Zigachev 		aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
3689b843c749SSergey Zigachev 		break;
3690b843c749SSergey Zigachev 	default:
3691b843c749SSergey Zigachev 		break;
3692b843c749SSergey Zigachev 	}
3693b843c749SSergey Zigachev 
3694b843c749SSergey Zigachev 	drm_object_attach_property(&aconnector->base.base,
3695b843c749SSergey Zigachev 				dm->ddev->mode_config.scaling_mode_property,
3696b843c749SSergey Zigachev 				DRM_MODE_SCALE_NONE);
3697b843c749SSergey Zigachev 
3698b843c749SSergey Zigachev 	drm_object_attach_property(&aconnector->base.base,
3699b843c749SSergey Zigachev 				adev->mode_info.underscan_property,
3700b843c749SSergey Zigachev 				UNDERSCAN_OFF);
3701b843c749SSergey Zigachev 	drm_object_attach_property(&aconnector->base.base,
3702b843c749SSergey Zigachev 				adev->mode_info.underscan_hborder_property,
3703b843c749SSergey Zigachev 				0);
3704b843c749SSergey Zigachev 	drm_object_attach_property(&aconnector->base.base,
3705b843c749SSergey Zigachev 				adev->mode_info.underscan_vborder_property,
3706b843c749SSergey Zigachev 				0);
3707b843c749SSergey Zigachev 	drm_object_attach_property(&aconnector->base.base,
3708b843c749SSergey Zigachev 				adev->mode_info.max_bpc_property,
3709b843c749SSergey Zigachev 				0);
3710b843c749SSergey Zigachev 
3711b843c749SSergey Zigachev }
3712b843c749SSergey Zigachev 
amdgpu_dm_i2c_xfer(struct i2c_adapter * i2c_adap,struct i2c_msg * msgs,int num)3713b843c749SSergey Zigachev static int amdgpu_dm_i2c_xfer(struct i2c_adapter *i2c_adap,
3714b843c749SSergey Zigachev 			      struct i2c_msg *msgs, int num)
3715b843c749SSergey Zigachev {
3716b843c749SSergey Zigachev 	struct amdgpu_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap);
3717b843c749SSergey Zigachev 	struct ddc_service *ddc_service = i2c->ddc_service;
3718b843c749SSergey Zigachev 	struct i2c_command cmd;
3719b843c749SSergey Zigachev 	int i;
3720b843c749SSergey Zigachev 	int result = -EIO;
3721b843c749SSergey Zigachev 
3722b843c749SSergey Zigachev 	cmd.payloads = kcalloc(num, sizeof(struct i2c_payload), GFP_KERNEL);
3723b843c749SSergey Zigachev 
3724b843c749SSergey Zigachev 	if (!cmd.payloads)
3725b843c749SSergey Zigachev 		return result;
3726b843c749SSergey Zigachev 
3727b843c749SSergey Zigachev 	cmd.number_of_payloads = num;
3728b843c749SSergey Zigachev 	cmd.engine = I2C_COMMAND_ENGINE_DEFAULT;
3729b843c749SSergey Zigachev 	cmd.speed = 100;
3730b843c749SSergey Zigachev 
3731b843c749SSergey Zigachev 	for (i = 0; i < num; i++) {
3732b843c749SSergey Zigachev 		cmd.payloads[i].write = !(msgs[i].flags & I2C_M_RD);
3733b843c749SSergey Zigachev 		cmd.payloads[i].address = msgs[i].addr;
3734b843c749SSergey Zigachev 		cmd.payloads[i].length = msgs[i].len;
3735b843c749SSergey Zigachev 		cmd.payloads[i].data = msgs[i].buf;
3736b843c749SSergey Zigachev 	}
3737b843c749SSergey Zigachev 
3738b843c749SSergey Zigachev 	if (dal_i2caux_submit_i2c_command(
3739b843c749SSergey Zigachev 			ddc_service->ctx->i2caux,
3740b843c749SSergey Zigachev 			ddc_service->ddc_pin,
3741b843c749SSergey Zigachev 			&cmd))
3742b843c749SSergey Zigachev 		result = num;
3743b843c749SSergey Zigachev 
3744b843c749SSergey Zigachev 	kfree(cmd.payloads);
3745b843c749SSergey Zigachev 	return result;
3746b843c749SSergey Zigachev }
3747b843c749SSergey Zigachev 
amdgpu_dm_i2c_func(struct i2c_adapter * adap)3748b843c749SSergey Zigachev static u32 amdgpu_dm_i2c_func(struct i2c_adapter *adap)
3749b843c749SSergey Zigachev {
3750b843c749SSergey Zigachev 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
3751b843c749SSergey Zigachev }
3752b843c749SSergey Zigachev 
3753b843c749SSergey Zigachev static const struct i2c_algorithm amdgpu_dm_i2c_algo = {
3754b843c749SSergey Zigachev 	.master_xfer = amdgpu_dm_i2c_xfer,
3755b843c749SSergey Zigachev 	.functionality = amdgpu_dm_i2c_func,
3756b843c749SSergey Zigachev };
3757b843c749SSergey Zigachev 
3758b843c749SSergey Zigachev static struct amdgpu_i2c_adapter *
create_i2c(struct ddc_service * ddc_service,int link_index,int * res)3759b843c749SSergey Zigachev create_i2c(struct ddc_service *ddc_service,
3760b843c749SSergey Zigachev 	   int link_index,
3761b843c749SSergey Zigachev 	   int *res)
3762b843c749SSergey Zigachev {
3763b843c749SSergey Zigachev 	struct amdgpu_device *adev = ddc_service->ctx->driver_context;
3764b843c749SSergey Zigachev 	struct amdgpu_i2c_adapter *i2c;
3765b843c749SSergey Zigachev 
3766b843c749SSergey Zigachev 	i2c = kzalloc(sizeof(struct amdgpu_i2c_adapter), GFP_KERNEL);
3767b843c749SSergey Zigachev 	if (!i2c)
3768b843c749SSergey Zigachev 		return NULL;
3769*78973132SSergey Zigachev #if 0
3770b843c749SSergey Zigachev 	i2c->base.owner = THIS_MODULE;
3771b843c749SSergey Zigachev 	i2c->base.class = I2C_CLASS_DDC;
3772*78973132SSergey Zigachev #endif
3773b843c749SSergey Zigachev 	i2c->base.dev.parent = &adev->pdev->dev;
3774b843c749SSergey Zigachev 	i2c->base.algo = &amdgpu_dm_i2c_algo;
3775b843c749SSergey Zigachev 	snprintf(i2c->base.name, sizeof(i2c->base.name), "AMDGPU DM i2c hw bus %d", link_index);
3776b843c749SSergey Zigachev 	i2c_set_adapdata(&i2c->base, i2c);
3777b843c749SSergey Zigachev 	i2c->ddc_service = ddc_service;
3778b843c749SSergey Zigachev 
3779b843c749SSergey Zigachev 	return i2c;
3780b843c749SSergey Zigachev }
3781b843c749SSergey Zigachev 
3782b843c749SSergey Zigachev 
3783b843c749SSergey Zigachev /* Note: this function assumes that dc_link_detect() was called for the
3784b843c749SSergey Zigachev  * dc_link which will be represented by this aconnector.
3785b843c749SSergey Zigachev  */
amdgpu_dm_connector_init(struct amdgpu_display_manager * dm,struct amdgpu_dm_connector * aconnector,uint32_t link_index,struct amdgpu_encoder * aencoder)3786b843c749SSergey Zigachev static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
3787b843c749SSergey Zigachev 				    struct amdgpu_dm_connector *aconnector,
3788b843c749SSergey Zigachev 				    uint32_t link_index,
3789b843c749SSergey Zigachev 				    struct amdgpu_encoder *aencoder)
3790b843c749SSergey Zigachev {
3791b843c749SSergey Zigachev 	int res = 0;
3792b843c749SSergey Zigachev 	int connector_type;
3793b843c749SSergey Zigachev 	struct dc *dc = dm->dc;
3794b843c749SSergey Zigachev 	struct dc_link *link = dc_get_link_at_index(dc, link_index);
3795b843c749SSergey Zigachev 	struct amdgpu_i2c_adapter *i2c;
3796b843c749SSergey Zigachev 
3797b843c749SSergey Zigachev 	link->priv = aconnector;
3798b843c749SSergey Zigachev 
3799b843c749SSergey Zigachev 	DRM_DEBUG_DRIVER("%s()\n", __func__);
3800b843c749SSergey Zigachev 
3801b843c749SSergey Zigachev 	i2c = create_i2c(link->ddc, link->link_index, &res);
3802b843c749SSergey Zigachev 	if (!i2c) {
3803b843c749SSergey Zigachev 		DRM_ERROR("Failed to create i2c adapter data\n");
3804b843c749SSergey Zigachev 		return -ENOMEM;
3805b843c749SSergey Zigachev 	}
3806b843c749SSergey Zigachev 
3807b843c749SSergey Zigachev 	aconnector->i2c = i2c;
3808b843c749SSergey Zigachev 	res = i2c_add_adapter(&i2c->base);
3809b843c749SSergey Zigachev 
3810b843c749SSergey Zigachev 	if (res) {
3811b843c749SSergey Zigachev 		DRM_ERROR("Failed to register hw i2c %d\n", link->link_index);
3812b843c749SSergey Zigachev 		goto out_free;
3813b843c749SSergey Zigachev 	}
3814b843c749SSergey Zigachev 
3815b843c749SSergey Zigachev 	connector_type = to_drm_connector_type(link->connector_signal);
3816b843c749SSergey Zigachev 
3817b843c749SSergey Zigachev 	res = drm_connector_init(
3818b843c749SSergey Zigachev 			dm->ddev,
3819b843c749SSergey Zigachev 			&aconnector->base,
3820b843c749SSergey Zigachev 			&amdgpu_dm_connector_funcs,
3821b843c749SSergey Zigachev 			connector_type);
3822b843c749SSergey Zigachev 
3823b843c749SSergey Zigachev 	if (res) {
3824b843c749SSergey Zigachev 		DRM_ERROR("connector_init failed\n");
3825b843c749SSergey Zigachev 		aconnector->connector_id = -1;
3826b843c749SSergey Zigachev 		goto out_free;
3827b843c749SSergey Zigachev 	}
3828b843c749SSergey Zigachev 
3829b843c749SSergey Zigachev 	drm_connector_helper_add(
3830b843c749SSergey Zigachev 			&aconnector->base,
3831b843c749SSergey Zigachev 			&amdgpu_dm_connector_helper_funcs);
3832b843c749SSergey Zigachev 
3833b843c749SSergey Zigachev 	amdgpu_dm_connector_init_helper(
3834b843c749SSergey Zigachev 		dm,
3835b843c749SSergey Zigachev 		aconnector,
3836b843c749SSergey Zigachev 		connector_type,
3837b843c749SSergey Zigachev 		link,
3838b843c749SSergey Zigachev 		link_index);
3839b843c749SSergey Zigachev 
3840*78973132SSergey Zigachev 	drm_mode_connector_attach_encoder(
3841b843c749SSergey Zigachev 		&aconnector->base, &aencoder->base);
3842b843c749SSergey Zigachev 
3843b843c749SSergey Zigachev 	drm_connector_register(&aconnector->base);
3844b843c749SSergey Zigachev #if defined(CONFIG_DEBUG_FS)
3845b843c749SSergey Zigachev 	res = connector_debugfs_init(aconnector);
3846b843c749SSergey Zigachev 	if (res) {
3847b843c749SSergey Zigachev 		DRM_ERROR("Failed to create debugfs for connector");
3848b843c749SSergey Zigachev 		goto out_free;
3849b843c749SSergey Zigachev 	}
3850b843c749SSergey Zigachev #endif
3851b843c749SSergey Zigachev 
3852b843c749SSergey Zigachev 	if (connector_type == DRM_MODE_CONNECTOR_DisplayPort
3853b843c749SSergey Zigachev 		|| connector_type == DRM_MODE_CONNECTOR_eDP)
3854b843c749SSergey Zigachev 		amdgpu_dm_initialize_dp_connector(dm, aconnector);
3855b843c749SSergey Zigachev 
3856b843c749SSergey Zigachev out_free:
3857b843c749SSergey Zigachev 	if (res) {
3858b843c749SSergey Zigachev 		kfree(i2c);
3859b843c749SSergey Zigachev 		aconnector->i2c = NULL;
3860b843c749SSergey Zigachev 	}
3861b843c749SSergey Zigachev 	return res;
3862b843c749SSergey Zigachev }
3863b843c749SSergey Zigachev 
amdgpu_dm_get_encoder_crtc_mask(struct amdgpu_device * adev)3864b843c749SSergey Zigachev int amdgpu_dm_get_encoder_crtc_mask(struct amdgpu_device *adev)
3865b843c749SSergey Zigachev {
3866b843c749SSergey Zigachev 	switch (adev->mode_info.num_crtc) {
3867b843c749SSergey Zigachev 	case 1:
3868b843c749SSergey Zigachev 		return 0x1;
3869b843c749SSergey Zigachev 	case 2:
3870b843c749SSergey Zigachev 		return 0x3;
3871b843c749SSergey Zigachev 	case 3:
3872b843c749SSergey Zigachev 		return 0x7;
3873b843c749SSergey Zigachev 	case 4:
3874b843c749SSergey Zigachev 		return 0xf;
3875b843c749SSergey Zigachev 	case 5:
3876b843c749SSergey Zigachev 		return 0x1f;
3877b843c749SSergey Zigachev 	case 6:
3878b843c749SSergey Zigachev 	default:
3879b843c749SSergey Zigachev 		return 0x3f;
3880b843c749SSergey Zigachev 	}
3881b843c749SSergey Zigachev }
3882b843c749SSergey Zigachev 
amdgpu_dm_encoder_init(struct drm_device * dev,struct amdgpu_encoder * aencoder,uint32_t link_index)3883b843c749SSergey Zigachev static int amdgpu_dm_encoder_init(struct drm_device *dev,
3884b843c749SSergey Zigachev 				  struct amdgpu_encoder *aencoder,
3885b843c749SSergey Zigachev 				  uint32_t link_index)
3886b843c749SSergey Zigachev {
3887b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev->dev_private;
3888b843c749SSergey Zigachev 
3889b843c749SSergey Zigachev 	int res = drm_encoder_init(dev,
3890b843c749SSergey Zigachev 				   &aencoder->base,
3891b843c749SSergey Zigachev 				   &amdgpu_dm_encoder_funcs,
3892b843c749SSergey Zigachev 				   DRM_MODE_ENCODER_TMDS,
3893b843c749SSergey Zigachev 				   NULL);
3894b843c749SSergey Zigachev 
3895b843c749SSergey Zigachev 	aencoder->base.possible_crtcs = amdgpu_dm_get_encoder_crtc_mask(adev);
3896b843c749SSergey Zigachev 
3897b843c749SSergey Zigachev 	if (!res)
3898b843c749SSergey Zigachev 		aencoder->encoder_id = link_index;
3899b843c749SSergey Zigachev 	else
3900b843c749SSergey Zigachev 		aencoder->encoder_id = -1;
3901b843c749SSergey Zigachev 
3902b843c749SSergey Zigachev 	drm_encoder_helper_add(&aencoder->base, &amdgpu_dm_encoder_helper_funcs);
3903b843c749SSergey Zigachev 
3904b843c749SSergey Zigachev 	return res;
3905b843c749SSergey Zigachev }
3906b843c749SSergey Zigachev 
manage_dm_interrupts(struct amdgpu_device * adev,struct amdgpu_crtc * acrtc,bool enable)3907b843c749SSergey Zigachev static void manage_dm_interrupts(struct amdgpu_device *adev,
3908b843c749SSergey Zigachev 				 struct amdgpu_crtc *acrtc,
3909b843c749SSergey Zigachev 				 bool enable)
3910b843c749SSergey Zigachev {
3911b843c749SSergey Zigachev 	/*
3912b843c749SSergey Zigachev 	 * this is not correct translation but will work as soon as VBLANK
3913b843c749SSergey Zigachev 	 * constant is the same as PFLIP
3914b843c749SSergey Zigachev 	 */
3915b843c749SSergey Zigachev 	int irq_type =
3916b843c749SSergey Zigachev 		amdgpu_display_crtc_idx_to_irq_type(
3917b843c749SSergey Zigachev 			adev,
3918b843c749SSergey Zigachev 			acrtc->crtc_id);
3919b843c749SSergey Zigachev 
3920b843c749SSergey Zigachev 	if (enable) {
3921b843c749SSergey Zigachev 		drm_crtc_vblank_on(&acrtc->base);
3922b843c749SSergey Zigachev 		amdgpu_irq_get(
3923b843c749SSergey Zigachev 			adev,
3924b843c749SSergey Zigachev 			&adev->pageflip_irq,
3925b843c749SSergey Zigachev 			irq_type);
3926b843c749SSergey Zigachev 	} else {
3927b843c749SSergey Zigachev 
3928b843c749SSergey Zigachev 		amdgpu_irq_put(
3929b843c749SSergey Zigachev 			adev,
3930b843c749SSergey Zigachev 			&adev->pageflip_irq,
3931b843c749SSergey Zigachev 			irq_type);
3932b843c749SSergey Zigachev 		drm_crtc_vblank_off(&acrtc->base);
3933b843c749SSergey Zigachev 	}
3934b843c749SSergey Zigachev }
3935b843c749SSergey Zigachev 
3936b843c749SSergey Zigachev static bool
is_scaling_state_different(const struct dm_connector_state * dm_state,const struct dm_connector_state * old_dm_state)3937b843c749SSergey Zigachev is_scaling_state_different(const struct dm_connector_state *dm_state,
3938b843c749SSergey Zigachev 			   const struct dm_connector_state *old_dm_state)
3939b843c749SSergey Zigachev {
3940b843c749SSergey Zigachev 	if (dm_state->scaling != old_dm_state->scaling)
3941b843c749SSergey Zigachev 		return true;
3942b843c749SSergey Zigachev 	if (!dm_state->underscan_enable && old_dm_state->underscan_enable) {
3943b843c749SSergey Zigachev 		if (old_dm_state->underscan_hborder != 0 && old_dm_state->underscan_vborder != 0)
3944b843c749SSergey Zigachev 			return true;
3945b843c749SSergey Zigachev 	} else  if (dm_state->underscan_enable && !old_dm_state->underscan_enable) {
3946b843c749SSergey Zigachev 		if (dm_state->underscan_hborder != 0 && dm_state->underscan_vborder != 0)
3947b843c749SSergey Zigachev 			return true;
3948b843c749SSergey Zigachev 	} else if (dm_state->underscan_hborder != old_dm_state->underscan_hborder ||
3949b843c749SSergey Zigachev 		   dm_state->underscan_vborder != old_dm_state->underscan_vborder)
3950b843c749SSergey Zigachev 		return true;
3951b843c749SSergey Zigachev 	return false;
3952b843c749SSergey Zigachev }
3953b843c749SSergey Zigachev 
remove_stream(struct amdgpu_device * adev,struct amdgpu_crtc * acrtc,struct dc_stream_state * stream)3954b843c749SSergey Zigachev static void remove_stream(struct amdgpu_device *adev,
3955b843c749SSergey Zigachev 			  struct amdgpu_crtc *acrtc,
3956b843c749SSergey Zigachev 			  struct dc_stream_state *stream)
3957b843c749SSergey Zigachev {
3958b843c749SSergey Zigachev 	/* this is the update mode case */
3959b843c749SSergey Zigachev 	if (adev->dm.freesync_module)
3960b843c749SSergey Zigachev 		mod_freesync_remove_stream(adev->dm.freesync_module, stream);
3961b843c749SSergey Zigachev 
3962b843c749SSergey Zigachev 	acrtc->otg_inst = -1;
3963b843c749SSergey Zigachev 	acrtc->enabled = false;
3964b843c749SSergey Zigachev }
3965b843c749SSergey Zigachev 
get_cursor_position(struct drm_plane * plane,struct drm_crtc * crtc,struct dc_cursor_position * position)3966b843c749SSergey Zigachev static int get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc,
3967b843c749SSergey Zigachev 			       struct dc_cursor_position *position)
3968b843c749SSergey Zigachev {
3969b843c749SSergey Zigachev 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
3970b843c749SSergey Zigachev 	int x, y;
3971b843c749SSergey Zigachev 	int xorigin = 0, yorigin = 0;
3972b843c749SSergey Zigachev 
3973b843c749SSergey Zigachev 	if (!crtc || !plane->state->fb) {
3974b843c749SSergey Zigachev 		position->enable = false;
3975b843c749SSergey Zigachev 		position->x = 0;
3976b843c749SSergey Zigachev 		position->y = 0;
3977b843c749SSergey Zigachev 		return 0;
3978b843c749SSergey Zigachev 	}
3979b843c749SSergey Zigachev 
3980b843c749SSergey Zigachev 	if ((plane->state->crtc_w > amdgpu_crtc->max_cursor_width) ||
3981b843c749SSergey Zigachev 	    (plane->state->crtc_h > amdgpu_crtc->max_cursor_height)) {
3982b843c749SSergey Zigachev 		DRM_ERROR("%s: bad cursor width or height %d x %d\n",
3983b843c749SSergey Zigachev 			  __func__,
3984b843c749SSergey Zigachev 			  plane->state->crtc_w,
3985b843c749SSergey Zigachev 			  plane->state->crtc_h);
3986b843c749SSergey Zigachev 		return -EINVAL;
3987b843c749SSergey Zigachev 	}
3988b843c749SSergey Zigachev 
3989b843c749SSergey Zigachev 	x = plane->state->crtc_x;
3990b843c749SSergey Zigachev 	y = plane->state->crtc_y;
3991b843c749SSergey Zigachev 	/* avivo cursor are offset into the total surface */
3992b843c749SSergey Zigachev 	x += crtc->primary->state->src_x >> 16;
3993b843c749SSergey Zigachev 	y += crtc->primary->state->src_y >> 16;
3994b843c749SSergey Zigachev 	if (x < 0) {
3995b843c749SSergey Zigachev 		xorigin = min(-x, amdgpu_crtc->max_cursor_width - 1);
3996b843c749SSergey Zigachev 		x = 0;
3997b843c749SSergey Zigachev 	}
3998b843c749SSergey Zigachev 	if (y < 0) {
3999b843c749SSergey Zigachev 		yorigin = min(-y, amdgpu_crtc->max_cursor_height - 1);
4000b843c749SSergey Zigachev 		y = 0;
4001b843c749SSergey Zigachev 	}
4002b843c749SSergey Zigachev 	position->enable = true;
4003b843c749SSergey Zigachev 	position->x = x;
4004b843c749SSergey Zigachev 	position->y = y;
4005b843c749SSergey Zigachev 	position->x_hotspot = xorigin;
4006b843c749SSergey Zigachev 	position->y_hotspot = yorigin;
4007b843c749SSergey Zigachev 
4008b843c749SSergey Zigachev 	return 0;
4009b843c749SSergey Zigachev }
4010b843c749SSergey Zigachev 
handle_cursor_update(struct drm_plane * plane,struct drm_plane_state * old_plane_state)4011b843c749SSergey Zigachev static void handle_cursor_update(struct drm_plane *plane,
4012b843c749SSergey Zigachev 				 struct drm_plane_state *old_plane_state)
4013b843c749SSergey Zigachev {
4014b843c749SSergey Zigachev 	struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(plane->state->fb);
4015b843c749SSergey Zigachev 	struct drm_crtc *crtc = afb ? plane->state->crtc : old_plane_state->crtc;
4016b843c749SSergey Zigachev 	struct dm_crtc_state *crtc_state = crtc ? to_dm_crtc_state(crtc->state) : NULL;
4017b843c749SSergey Zigachev 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
4018b843c749SSergey Zigachev 	uint64_t address = afb ? afb->address : 0;
4019b843c749SSergey Zigachev 	struct dc_cursor_position position;
4020b843c749SSergey Zigachev 	struct dc_cursor_attributes attributes;
4021b843c749SSergey Zigachev 	int ret;
4022b843c749SSergey Zigachev 
4023b843c749SSergey Zigachev 	if (!plane->state->fb && !old_plane_state->fb)
4024b843c749SSergey Zigachev 		return;
4025b843c749SSergey Zigachev 
4026b843c749SSergey Zigachev 	DRM_DEBUG_DRIVER("%s: crtc_id=%d with size %d to %d\n",
4027b843c749SSergey Zigachev 			 __func__,
4028b843c749SSergey Zigachev 			 amdgpu_crtc->crtc_id,
4029b843c749SSergey Zigachev 			 plane->state->crtc_w,
4030b843c749SSergey Zigachev 			 plane->state->crtc_h);
4031b843c749SSergey Zigachev 
4032b843c749SSergey Zigachev 	ret = get_cursor_position(plane, crtc, &position);
4033b843c749SSergey Zigachev 	if (ret)
4034b843c749SSergey Zigachev 		return;
4035b843c749SSergey Zigachev 
4036b843c749SSergey Zigachev 	if (!position.enable) {
4037b843c749SSergey Zigachev 		/* turn off cursor */
4038b843c749SSergey Zigachev 		if (crtc_state && crtc_state->stream)
4039b843c749SSergey Zigachev 			dc_stream_set_cursor_position(crtc_state->stream,
4040b843c749SSergey Zigachev 						      &position);
4041b843c749SSergey Zigachev 		return;
4042b843c749SSergey Zigachev 	}
4043b843c749SSergey Zigachev 
4044b843c749SSergey Zigachev 	amdgpu_crtc->cursor_width = plane->state->crtc_w;
4045b843c749SSergey Zigachev 	amdgpu_crtc->cursor_height = plane->state->crtc_h;
4046b843c749SSergey Zigachev 
4047b843c749SSergey Zigachev 	memset(&attributes, 0, sizeof(attributes));
4048b843c749SSergey Zigachev 	attributes.address.high_part = upper_32_bits(address);
4049b843c749SSergey Zigachev 	attributes.address.low_part  = lower_32_bits(address);
4050b843c749SSergey Zigachev 	attributes.width             = plane->state->crtc_w;
4051b843c749SSergey Zigachev 	attributes.height            = plane->state->crtc_h;
4052b843c749SSergey Zigachev 	attributes.color_format      = CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA;
4053b843c749SSergey Zigachev 	attributes.rotation_angle    = 0;
4054b843c749SSergey Zigachev 	attributes.attribute_flags.value = 0;
4055b843c749SSergey Zigachev 
4056b843c749SSergey Zigachev 	attributes.pitch = attributes.width;
4057b843c749SSergey Zigachev 
4058b843c749SSergey Zigachev 	if (crtc_state->stream) {
4059b843c749SSergey Zigachev 		if (!dc_stream_set_cursor_attributes(crtc_state->stream,
4060b843c749SSergey Zigachev 							 &attributes))
4061b843c749SSergey Zigachev 			DRM_ERROR("DC failed to set cursor attributes\n");
4062b843c749SSergey Zigachev 
4063b843c749SSergey Zigachev 		if (!dc_stream_set_cursor_position(crtc_state->stream,
4064b843c749SSergey Zigachev 						   &position))
4065b843c749SSergey Zigachev 			DRM_ERROR("DC failed to set cursor position\n");
4066b843c749SSergey Zigachev 	}
4067b843c749SSergey Zigachev }
4068b843c749SSergey Zigachev 
prepare_flip_isr(struct amdgpu_crtc * acrtc)4069b843c749SSergey Zigachev static void prepare_flip_isr(struct amdgpu_crtc *acrtc)
4070b843c749SSergey Zigachev {
4071b843c749SSergey Zigachev 
4072b843c749SSergey Zigachev 	assert_spin_locked(&acrtc->base.dev->event_lock);
4073b843c749SSergey Zigachev 	WARN_ON(acrtc->event);
4074b843c749SSergey Zigachev 
4075b843c749SSergey Zigachev 	acrtc->event = acrtc->base.state->event;
4076b843c749SSergey Zigachev 
4077b843c749SSergey Zigachev 	/* Set the flip status */
4078b843c749SSergey Zigachev 	acrtc->pflip_status = AMDGPU_FLIP_SUBMITTED;
4079b843c749SSergey Zigachev 
4080b843c749SSergey Zigachev 	/* Mark this event as consumed */
4081b843c749SSergey Zigachev 	acrtc->base.state->event = NULL;
4082b843c749SSergey Zigachev 
4083b843c749SSergey Zigachev 	DRM_DEBUG_DRIVER("crtc:%d, pflip_stat:AMDGPU_FLIP_SUBMITTED\n",
4084b843c749SSergey Zigachev 						 acrtc->crtc_id);
4085b843c749SSergey Zigachev }
4086b843c749SSergey Zigachev 
4087b843c749SSergey Zigachev /*
4088b843c749SSergey Zigachev  * Executes flip
4089b843c749SSergey Zigachev  *
4090b843c749SSergey Zigachev  * Waits on all BO's fences and for proper vblank count
4091b843c749SSergey Zigachev  */
amdgpu_dm_do_flip(struct drm_crtc * crtc,struct drm_framebuffer * fb,uint32_t target,struct dc_state * state)4092b843c749SSergey Zigachev static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
4093b843c749SSergey Zigachev 			      struct drm_framebuffer *fb,
4094b843c749SSergey Zigachev 			      uint32_t target,
4095b843c749SSergey Zigachev 			      struct dc_state *state)
4096b843c749SSergey Zigachev {
4097b843c749SSergey Zigachev 	unsigned long flags;
4098b843c749SSergey Zigachev 	uint32_t target_vblank;
4099b843c749SSergey Zigachev 	int r, vpos, hpos;
4100b843c749SSergey Zigachev 	struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
4101b843c749SSergey Zigachev 	struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(fb);
4102b843c749SSergey Zigachev 	struct amdgpu_bo *abo = gem_to_amdgpu_bo(fb->obj[0]);
4103b843c749SSergey Zigachev 	struct amdgpu_device *adev = crtc->dev->dev_private;
4104b843c749SSergey Zigachev 	bool async_flip = (crtc->state->pageflip_flags & DRM_MODE_PAGE_FLIP_ASYNC) != 0;
4105b843c749SSergey Zigachev 	struct dc_flip_addrs addr = { {0} };
4106b843c749SSergey Zigachev 	/* TODO eliminate or rename surface_update */
4107b843c749SSergey Zigachev 	struct dc_surface_update surface_updates[1] = { {0} };
4108b843c749SSergey Zigachev 	struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state);
4109b843c749SSergey Zigachev 
4110b843c749SSergey Zigachev 
4111b843c749SSergey Zigachev 	/* Prepare wait for target vblank early - before the fence-waits */
4112b843c749SSergey Zigachev 	target_vblank = target - (uint32_t)drm_crtc_vblank_count(crtc) +
4113b843c749SSergey Zigachev 			amdgpu_get_vblank_counter_kms(crtc->dev, acrtc->crtc_id);
4114b843c749SSergey Zigachev 
4115b843c749SSergey Zigachev 	/* TODO This might fail and hence better not used, wait
4116b843c749SSergey Zigachev 	 * explicitly on fences instead
4117b843c749SSergey Zigachev 	 * and in general should be called for
4118b843c749SSergey Zigachev 	 * blocking commit to as per framework helpers
4119b843c749SSergey Zigachev 	 */
4120b843c749SSergey Zigachev 	r = amdgpu_bo_reserve(abo, true);
4121b843c749SSergey Zigachev 	if (unlikely(r != 0)) {
4122b843c749SSergey Zigachev 		DRM_ERROR("failed to reserve buffer before flip\n");
4123b843c749SSergey Zigachev 		WARN_ON(1);
4124b843c749SSergey Zigachev 	}
4125b843c749SSergey Zigachev 
4126b843c749SSergey Zigachev 	/* Wait for all fences on this FB */
4127b843c749SSergey Zigachev 	WARN_ON(reservation_object_wait_timeout_rcu(abo->tbo.resv, true, false,
4128b843c749SSergey Zigachev 								    MAX_SCHEDULE_TIMEOUT) < 0);
4129b843c749SSergey Zigachev 
4130b843c749SSergey Zigachev 	amdgpu_bo_unreserve(abo);
4131b843c749SSergey Zigachev 
4132b843c749SSergey Zigachev 	/* Wait until we're out of the vertical blank period before the one
4133b843c749SSergey Zigachev 	 * targeted by the flip
4134b843c749SSergey Zigachev 	 */
4135b843c749SSergey Zigachev 	while ((acrtc->enabled &&
4136b843c749SSergey Zigachev 		(amdgpu_display_get_crtc_scanoutpos(adev->ddev, acrtc->crtc_id,
4137b843c749SSergey Zigachev 						    0, &vpos, &hpos, NULL,
4138b843c749SSergey Zigachev 						    NULL, &crtc->hwmode)
4139b843c749SSergey Zigachev 		 & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) ==
4140b843c749SSergey Zigachev 		(DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) &&
4141b843c749SSergey Zigachev 		(int)(target_vblank -
4142b843c749SSergey Zigachev 		  amdgpu_get_vblank_counter_kms(adev->ddev, acrtc->crtc_id)) > 0)) {
4143b843c749SSergey Zigachev 		usleep_range(1000, 1100);
4144b843c749SSergey Zigachev 	}
4145b843c749SSergey Zigachev 
4146b843c749SSergey Zigachev 	/* Flip */
4147b843c749SSergey Zigachev 	spin_lock_irqsave(&crtc->dev->event_lock, flags);
4148b843c749SSergey Zigachev 
4149b843c749SSergey Zigachev 	WARN_ON(acrtc->pflip_status != AMDGPU_FLIP_NONE);
4150b843c749SSergey Zigachev 	WARN_ON(!acrtc_state->stream);
4151b843c749SSergey Zigachev 
4152b843c749SSergey Zigachev 	addr.address.grph.addr.low_part = lower_32_bits(afb->address);
4153b843c749SSergey Zigachev 	addr.address.grph.addr.high_part = upper_32_bits(afb->address);
4154b843c749SSergey Zigachev 	addr.flip_immediate = async_flip;
4155b843c749SSergey Zigachev 
4156b843c749SSergey Zigachev 
4157b843c749SSergey Zigachev 	if (acrtc->base.state->event)
4158b843c749SSergey Zigachev 		prepare_flip_isr(acrtc);
4159b843c749SSergey Zigachev 
4160b843c749SSergey Zigachev 	spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
4161b843c749SSergey Zigachev 
4162b843c749SSergey Zigachev 	surface_updates->surface = dc_stream_get_status(acrtc_state->stream)->plane_states[0];
4163b843c749SSergey Zigachev 	surface_updates->flip_addr = &addr;
4164b843c749SSergey Zigachev 
4165b843c749SSergey Zigachev 	dc_commit_updates_for_stream(adev->dm.dc,
4166b843c749SSergey Zigachev 					     surface_updates,
4167b843c749SSergey Zigachev 					     1,
4168b843c749SSergey Zigachev 					     acrtc_state->stream,
4169b843c749SSergey Zigachev 					     NULL,
4170b843c749SSergey Zigachev 					     &surface_updates->surface,
4171b843c749SSergey Zigachev 					     state);
4172b843c749SSergey Zigachev 
4173b843c749SSergey Zigachev 	DRM_DEBUG_DRIVER("%s Flipping to hi: 0x%x, low: 0x%x \n",
4174b843c749SSergey Zigachev 			 __func__,
4175b843c749SSergey Zigachev 			 addr.address.grph.addr.high_part,
4176b843c749SSergey Zigachev 			 addr.address.grph.addr.low_part);
4177b843c749SSergey Zigachev }
4178b843c749SSergey Zigachev 
4179b843c749SSergey Zigachev /*
4180b843c749SSergey Zigachev  * TODO this whole function needs to go
4181b843c749SSergey Zigachev  *
4182b843c749SSergey Zigachev  * dc_surface_update is needlessly complex. See if we can just replace this
4183b843c749SSergey Zigachev  * with a dc_plane_state and follow the atomic model a bit more closely here.
4184b843c749SSergey Zigachev  */
commit_planes_to_stream(struct dc * dc,struct dc_plane_state ** plane_states,uint8_t new_plane_count,struct dm_crtc_state * dm_new_crtc_state,struct dm_crtc_state * dm_old_crtc_state,struct dc_state * state)4185b843c749SSergey Zigachev static bool commit_planes_to_stream(
4186b843c749SSergey Zigachev 		struct dc *dc,
4187b843c749SSergey Zigachev 		struct dc_plane_state **plane_states,
4188b843c749SSergey Zigachev 		uint8_t new_plane_count,
4189b843c749SSergey Zigachev 		struct dm_crtc_state *dm_new_crtc_state,
4190b843c749SSergey Zigachev 		struct dm_crtc_state *dm_old_crtc_state,
4191b843c749SSergey Zigachev 		struct dc_state *state)
4192b843c749SSergey Zigachev {
4193b843c749SSergey Zigachev 	/* no need to dynamically allocate this. it's pretty small */
4194b843c749SSergey Zigachev 	struct dc_surface_update updates[MAX_SURFACES];
4195b843c749SSergey Zigachev 	struct dc_flip_addrs *flip_addr;
4196b843c749SSergey Zigachev 	struct dc_plane_info *plane_info;
4197b843c749SSergey Zigachev 	struct dc_scaling_info *scaling_info;
4198b843c749SSergey Zigachev 	int i;
4199b843c749SSergey Zigachev 	struct dc_stream_state *dc_stream = dm_new_crtc_state->stream;
4200b843c749SSergey Zigachev 	struct dc_stream_update *stream_update =
4201b843c749SSergey Zigachev 			kzalloc(sizeof(struct dc_stream_update), GFP_KERNEL);
4202b843c749SSergey Zigachev 
4203b843c749SSergey Zigachev 	if (!stream_update) {
4204b843c749SSergey Zigachev 		BREAK_TO_DEBUGGER();
4205b843c749SSergey Zigachev 		return false;
4206b843c749SSergey Zigachev 	}
4207b843c749SSergey Zigachev 
4208b843c749SSergey Zigachev 	flip_addr = kcalloc(MAX_SURFACES, sizeof(struct dc_flip_addrs),
4209b843c749SSergey Zigachev 			    GFP_KERNEL);
4210b843c749SSergey Zigachev 	plane_info = kcalloc(MAX_SURFACES, sizeof(struct dc_plane_info),
4211b843c749SSergey Zigachev 			     GFP_KERNEL);
4212b843c749SSergey Zigachev 	scaling_info = kcalloc(MAX_SURFACES, sizeof(struct dc_scaling_info),
4213b843c749SSergey Zigachev 			       GFP_KERNEL);
4214b843c749SSergey Zigachev 
4215b843c749SSergey Zigachev 	if (!flip_addr || !plane_info || !scaling_info) {
4216b843c749SSergey Zigachev 		kfree(flip_addr);
4217b843c749SSergey Zigachev 		kfree(plane_info);
4218b843c749SSergey Zigachev 		kfree(scaling_info);
4219b843c749SSergey Zigachev 		kfree(stream_update);
4220b843c749SSergey Zigachev 		return false;
4221b843c749SSergey Zigachev 	}
4222b843c749SSergey Zigachev 
4223b843c749SSergey Zigachev 	memset(updates, 0, sizeof(updates));
4224b843c749SSergey Zigachev 
4225b843c749SSergey Zigachev 	stream_update->src = dc_stream->src;
4226b843c749SSergey Zigachev 	stream_update->dst = dc_stream->dst;
4227b843c749SSergey Zigachev 	stream_update->out_transfer_func = dc_stream->out_transfer_func;
4228b843c749SSergey Zigachev 
4229b843c749SSergey Zigachev 	for (i = 0; i < new_plane_count; i++) {
4230b843c749SSergey Zigachev 		updates[i].surface = plane_states[i];
4231b843c749SSergey Zigachev 		updates[i].gamma =
4232b843c749SSergey Zigachev 			(struct dc_gamma *)plane_states[i]->gamma_correction;
4233b843c749SSergey Zigachev 		updates[i].in_transfer_func = plane_states[i]->in_transfer_func;
4234b843c749SSergey Zigachev 		flip_addr[i].address = plane_states[i]->address;
4235b843c749SSergey Zigachev 		flip_addr[i].flip_immediate = plane_states[i]->flip_immediate;
4236b843c749SSergey Zigachev 		plane_info[i].color_space = plane_states[i]->color_space;
4237b843c749SSergey Zigachev 		plane_info[i].format = plane_states[i]->format;
4238b843c749SSergey Zigachev 		plane_info[i].plane_size = plane_states[i]->plane_size;
4239b843c749SSergey Zigachev 		plane_info[i].rotation = plane_states[i]->rotation;
4240b843c749SSergey Zigachev 		plane_info[i].horizontal_mirror = plane_states[i]->horizontal_mirror;
4241b843c749SSergey Zigachev 		plane_info[i].stereo_format = plane_states[i]->stereo_format;
4242b843c749SSergey Zigachev 		plane_info[i].tiling_info = plane_states[i]->tiling_info;
4243b843c749SSergey Zigachev 		plane_info[i].visible = plane_states[i]->visible;
4244b843c749SSergey Zigachev 		plane_info[i].per_pixel_alpha = plane_states[i]->per_pixel_alpha;
4245b843c749SSergey Zigachev 		plane_info[i].dcc = plane_states[i]->dcc;
4246b843c749SSergey Zigachev 		scaling_info[i].scaling_quality = plane_states[i]->scaling_quality;
4247b843c749SSergey Zigachev 		scaling_info[i].src_rect = plane_states[i]->src_rect;
4248b843c749SSergey Zigachev 		scaling_info[i].dst_rect = plane_states[i]->dst_rect;
4249b843c749SSergey Zigachev 		scaling_info[i].clip_rect = plane_states[i]->clip_rect;
4250b843c749SSergey Zigachev 
4251b843c749SSergey Zigachev 		updates[i].flip_addr = &flip_addr[i];
4252b843c749SSergey Zigachev 		updates[i].plane_info = &plane_info[i];
4253b843c749SSergey Zigachev 		updates[i].scaling_info = &scaling_info[i];
4254b843c749SSergey Zigachev 	}
4255b843c749SSergey Zigachev 
4256b843c749SSergey Zigachev 	dc_commit_updates_for_stream(
4257b843c749SSergey Zigachev 			dc,
4258b843c749SSergey Zigachev 			updates,
4259b843c749SSergey Zigachev 			new_plane_count,
4260b843c749SSergey Zigachev 			dc_stream, stream_update, plane_states, state);
4261b843c749SSergey Zigachev 
4262b843c749SSergey Zigachev 	kfree(flip_addr);
4263b843c749SSergey Zigachev 	kfree(plane_info);
4264b843c749SSergey Zigachev 	kfree(scaling_info);
4265b843c749SSergey Zigachev 	kfree(stream_update);
4266b843c749SSergey Zigachev 	return true;
4267b843c749SSergey Zigachev }
4268b843c749SSergey Zigachev 
amdgpu_dm_commit_planes(struct drm_atomic_state * state,struct drm_device * dev,struct amdgpu_display_manager * dm,struct drm_crtc * pcrtc,bool * wait_for_vblank)4269b843c749SSergey Zigachev static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
4270b843c749SSergey Zigachev 				    struct drm_device *dev,
4271b843c749SSergey Zigachev 				    struct amdgpu_display_manager *dm,
4272b843c749SSergey Zigachev 				    struct drm_crtc *pcrtc,
4273b843c749SSergey Zigachev 				    bool *wait_for_vblank)
4274b843c749SSergey Zigachev {
4275b843c749SSergey Zigachev 	uint32_t i;
4276b843c749SSergey Zigachev 	struct drm_plane *plane;
4277b843c749SSergey Zigachev 	struct drm_plane_state *old_plane_state, *new_plane_state;
4278b843c749SSergey Zigachev 	struct dc_stream_state *dc_stream_attach;
4279b843c749SSergey Zigachev 	struct dc_plane_state *plane_states_constructed[MAX_SURFACES];
4280b843c749SSergey Zigachev 	struct amdgpu_crtc *acrtc_attach = to_amdgpu_crtc(pcrtc);
4281b843c749SSergey Zigachev 	struct drm_crtc_state *new_pcrtc_state =
4282b843c749SSergey Zigachev 			drm_atomic_get_new_crtc_state(state, pcrtc);
4283b843c749SSergey Zigachev 	struct dm_crtc_state *acrtc_state = to_dm_crtc_state(new_pcrtc_state);
4284b843c749SSergey Zigachev 	struct dm_crtc_state *dm_old_crtc_state =
4285b843c749SSergey Zigachev 			to_dm_crtc_state(drm_atomic_get_old_crtc_state(state, pcrtc));
4286b843c749SSergey Zigachev 	struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
4287b843c749SSergey Zigachev 	int planes_count = 0;
4288b843c749SSergey Zigachev 	unsigned long flags;
4289b843c749SSergey Zigachev 
4290b843c749SSergey Zigachev 	/* update planes when needed */
4291b843c749SSergey Zigachev 	for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
4292b843c749SSergey Zigachev 		struct drm_crtc *crtc = new_plane_state->crtc;
4293b843c749SSergey Zigachev 		struct drm_crtc_state *new_crtc_state;
4294b843c749SSergey Zigachev 		struct drm_framebuffer *fb = new_plane_state->fb;
4295b843c749SSergey Zigachev 		bool pflip_needed;
4296b843c749SSergey Zigachev 		struct dm_plane_state *dm_new_plane_state = to_dm_plane_state(new_plane_state);
4297b843c749SSergey Zigachev 
4298b843c749SSergey Zigachev 		if (plane->type == DRM_PLANE_TYPE_CURSOR) {
4299b843c749SSergey Zigachev 			handle_cursor_update(plane, old_plane_state);
4300b843c749SSergey Zigachev 			continue;
4301b843c749SSergey Zigachev 		}
4302b843c749SSergey Zigachev 
4303b843c749SSergey Zigachev 		if (!fb || !crtc || pcrtc != crtc)
4304b843c749SSergey Zigachev 			continue;
4305b843c749SSergey Zigachev 
4306b843c749SSergey Zigachev 		new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
4307b843c749SSergey Zigachev 		if (!new_crtc_state->active)
4308b843c749SSergey Zigachev 			continue;
4309b843c749SSergey Zigachev 
4310b843c749SSergey Zigachev 		pflip_needed = !state->allow_modeset;
4311b843c749SSergey Zigachev 
4312b843c749SSergey Zigachev 		spin_lock_irqsave(&crtc->dev->event_lock, flags);
4313b843c749SSergey Zigachev 		if (acrtc_attach->pflip_status != AMDGPU_FLIP_NONE) {
4314b843c749SSergey Zigachev 			DRM_ERROR("%s: acrtc %d, already busy\n",
4315b843c749SSergey Zigachev 				  __func__,
4316b843c749SSergey Zigachev 				  acrtc_attach->crtc_id);
4317b843c749SSergey Zigachev 			/* In commit tail framework this cannot happen */
4318b843c749SSergey Zigachev 			WARN_ON(1);
4319b843c749SSergey Zigachev 		}
4320b843c749SSergey Zigachev 		spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
4321b843c749SSergey Zigachev 
4322b843c749SSergey Zigachev 		if (!pflip_needed || plane->type == DRM_PLANE_TYPE_OVERLAY) {
4323b843c749SSergey Zigachev 			WARN_ON(!dm_new_plane_state->dc_state);
4324b843c749SSergey Zigachev 
4325b843c749SSergey Zigachev 			plane_states_constructed[planes_count] = dm_new_plane_state->dc_state;
4326b843c749SSergey Zigachev 
4327b843c749SSergey Zigachev 			dc_stream_attach = acrtc_state->stream;
4328b843c749SSergey Zigachev 			planes_count++;
4329b843c749SSergey Zigachev 
4330b843c749SSergey Zigachev 		} else if (new_crtc_state->planes_changed) {
4331b843c749SSergey Zigachev 			/* Assume even ONE crtc with immediate flip means
4332b843c749SSergey Zigachev 			 * entire can't wait for VBLANK
4333b843c749SSergey Zigachev 			 * TODO Check if it's correct
4334b843c749SSergey Zigachev 			 */
4335b843c749SSergey Zigachev 			*wait_for_vblank =
4336b843c749SSergey Zigachev 					new_pcrtc_state->pageflip_flags & DRM_MODE_PAGE_FLIP_ASYNC ?
4337b843c749SSergey Zigachev 				false : true;
4338b843c749SSergey Zigachev 
4339b843c749SSergey Zigachev 			/* TODO: Needs rework for multiplane flip */
4340b843c749SSergey Zigachev 			if (plane->type == DRM_PLANE_TYPE_PRIMARY)
4341b843c749SSergey Zigachev 				drm_crtc_vblank_get(crtc);
4342b843c749SSergey Zigachev 
4343b843c749SSergey Zigachev 			amdgpu_dm_do_flip(
4344b843c749SSergey Zigachev 				crtc,
4345b843c749SSergey Zigachev 				fb,
4346b843c749SSergey Zigachev 				(uint32_t)drm_crtc_vblank_count(crtc) + *wait_for_vblank,
4347b843c749SSergey Zigachev 				dm_state->context);
4348b843c749SSergey Zigachev 		}
4349b843c749SSergey Zigachev 
4350b843c749SSergey Zigachev 	}
4351b843c749SSergey Zigachev 
4352b843c749SSergey Zigachev 	if (planes_count) {
4353b843c749SSergey Zigachev 		unsigned long flags;
4354b843c749SSergey Zigachev 
4355b843c749SSergey Zigachev 		if (new_pcrtc_state->event) {
4356b843c749SSergey Zigachev 
4357b843c749SSergey Zigachev 			drm_crtc_vblank_get(pcrtc);
4358b843c749SSergey Zigachev 
4359b843c749SSergey Zigachev 			spin_lock_irqsave(&pcrtc->dev->event_lock, flags);
4360b843c749SSergey Zigachev 			prepare_flip_isr(acrtc_attach);
4361b843c749SSergey Zigachev 			spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
4362b843c749SSergey Zigachev 		}
4363b843c749SSergey Zigachev 
4364b843c749SSergey Zigachev 
4365b843c749SSergey Zigachev 		if (false == commit_planes_to_stream(dm->dc,
4366b843c749SSergey Zigachev 							plane_states_constructed,
4367b843c749SSergey Zigachev 							planes_count,
4368b843c749SSergey Zigachev 							acrtc_state,
4369b843c749SSergey Zigachev 							dm_old_crtc_state,
4370b843c749SSergey Zigachev 							dm_state->context))
4371b843c749SSergey Zigachev 			dm_error("%s: Failed to attach plane!\n", __func__);
4372b843c749SSergey Zigachev 	} else {
4373b843c749SSergey Zigachev 		/*TODO BUG Here should go disable planes on CRTC. */
4374b843c749SSergey Zigachev 	}
4375b843c749SSergey Zigachev }
4376b843c749SSergey Zigachev 
4377b843c749SSergey Zigachev /**
4378b843c749SSergey Zigachev  * amdgpu_dm_crtc_copy_transient_flags - copy mirrored flags from DRM to DC
4379b843c749SSergey Zigachev  * @crtc_state: the DRM CRTC state
4380b843c749SSergey Zigachev  * @stream_state: the DC stream state.
4381b843c749SSergey Zigachev  *
4382b843c749SSergey Zigachev  * Copy the mirrored transient state flags from DRM, to DC. It is used to bring
4383b843c749SSergey Zigachev  * a dc_stream_state's flags in sync with a drm_crtc_state's flags.
4384b843c749SSergey Zigachev  */
amdgpu_dm_crtc_copy_transient_flags(struct drm_crtc_state * crtc_state,struct dc_stream_state * stream_state)4385b843c749SSergey Zigachev static void amdgpu_dm_crtc_copy_transient_flags(struct drm_crtc_state *crtc_state,
4386b843c749SSergey Zigachev 						struct dc_stream_state *stream_state)
4387b843c749SSergey Zigachev {
4388b843c749SSergey Zigachev 	stream_state->mode_changed = drm_atomic_crtc_needs_modeset(crtc_state);
4389b843c749SSergey Zigachev }
4390b843c749SSergey Zigachev 
amdgpu_dm_atomic_commit(struct drm_device * dev,struct drm_atomic_state * state,bool nonblock)4391b843c749SSergey Zigachev static int amdgpu_dm_atomic_commit(struct drm_device *dev,
4392b843c749SSergey Zigachev 				   struct drm_atomic_state *state,
4393b843c749SSergey Zigachev 				   bool nonblock)
4394b843c749SSergey Zigachev {
4395b843c749SSergey Zigachev 	struct drm_crtc *crtc;
4396b843c749SSergey Zigachev 	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
4397b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev->dev_private;
4398b843c749SSergey Zigachev 	int i;
4399b843c749SSergey Zigachev 
4400b843c749SSergey Zigachev 	/*
4401b843c749SSergey Zigachev 	 * We evade vblanks and pflips on crtc that
4402b843c749SSergey Zigachev 	 * should be changed. We do it here to flush & disable
4403b843c749SSergey Zigachev 	 * interrupts before drm_swap_state is called in drm_atomic_helper_commit
4404b843c749SSergey Zigachev 	 * it will update crtc->dm_crtc_state->stream pointer which is used in
4405b843c749SSergey Zigachev 	 * the ISRs.
4406b843c749SSergey Zigachev 	 */
4407b843c749SSergey Zigachev 	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
4408b843c749SSergey Zigachev 		struct dm_crtc_state *dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
4409b843c749SSergey Zigachev 		struct dm_crtc_state *dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
4410b843c749SSergey Zigachev 		struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
4411b843c749SSergey Zigachev 
4412b843c749SSergey Zigachev 		if (drm_atomic_crtc_needs_modeset(new_crtc_state)
4413b843c749SSergey Zigachev 		    && dm_old_crtc_state->stream) {
4414b843c749SSergey Zigachev 			/*
4415b843c749SSergey Zigachev 			 * CRC capture was enabled but not disabled.
4416b843c749SSergey Zigachev 			 * Release the vblank reference.
4417b843c749SSergey Zigachev 			 */
4418b843c749SSergey Zigachev 			if (dm_new_crtc_state->crc_enabled) {
4419b843c749SSergey Zigachev 				drm_crtc_vblank_put(crtc);
4420b843c749SSergey Zigachev 				dm_new_crtc_state->crc_enabled = false;
4421b843c749SSergey Zigachev 			}
4422b843c749SSergey Zigachev 
4423b843c749SSergey Zigachev 			manage_dm_interrupts(adev, acrtc, false);
4424b843c749SSergey Zigachev 		}
4425b843c749SSergey Zigachev 	}
4426b843c749SSergey Zigachev 	/* Add check here for SoC's that support hardware cursor plane, to
4427b843c749SSergey Zigachev 	 * unset legacy_cursor_update */
4428b843c749SSergey Zigachev 
4429b843c749SSergey Zigachev 	return drm_atomic_helper_commit(dev, state, nonblock);
4430b843c749SSergey Zigachev 
4431b843c749SSergey Zigachev 	/*TODO Handle EINTR, reenable IRQ*/
4432b843c749SSergey Zigachev }
4433b843c749SSergey Zigachev 
amdgpu_dm_atomic_commit_tail(struct drm_atomic_state * state)4434b843c749SSergey Zigachev static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
4435b843c749SSergey Zigachev {
4436b843c749SSergey Zigachev 	struct drm_device *dev = state->dev;
4437b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev->dev_private;
4438b843c749SSergey Zigachev 	struct amdgpu_display_manager *dm = &adev->dm;
4439b843c749SSergey Zigachev 	struct dm_atomic_state *dm_state;
4440b843c749SSergey Zigachev 	uint32_t i, j;
4441b843c749SSergey Zigachev 	struct drm_crtc *crtc;
4442b843c749SSergey Zigachev 	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
4443b843c749SSergey Zigachev 	unsigned long flags;
4444b843c749SSergey Zigachev 	bool wait_for_vblank = true;
4445b843c749SSergey Zigachev 	struct drm_connector *connector;
4446b843c749SSergey Zigachev 	struct drm_connector_state *old_con_state, *new_con_state;
4447b843c749SSergey Zigachev 	struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
4448b843c749SSergey Zigachev 	int crtc_disable_count = 0;
4449b843c749SSergey Zigachev 
4450b843c749SSergey Zigachev 	drm_atomic_helper_update_legacy_modeset_state(dev, state);
4451b843c749SSergey Zigachev 
4452b843c749SSergey Zigachev 	dm_state = to_dm_atomic_state(state);
4453b843c749SSergey Zigachev 
4454b843c749SSergey Zigachev 	/* update changed items */
4455b843c749SSergey Zigachev 	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
4456b843c749SSergey Zigachev 		struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
4457b843c749SSergey Zigachev 
4458b843c749SSergey Zigachev 		dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
4459b843c749SSergey Zigachev 		dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
4460b843c749SSergey Zigachev 
4461b843c749SSergey Zigachev 		DRM_DEBUG_DRIVER(
4462b843c749SSergey Zigachev 			"amdgpu_crtc id:%d crtc_state_flags: enable:%d, active:%d, "
4463b843c749SSergey Zigachev 			"planes_changed:%d, mode_changed:%d,active_changed:%d,"
4464b843c749SSergey Zigachev 			"connectors_changed:%d\n",
4465b843c749SSergey Zigachev 			acrtc->crtc_id,
4466b843c749SSergey Zigachev 			new_crtc_state->enable,
4467b843c749SSergey Zigachev 			new_crtc_state->active,
4468b843c749SSergey Zigachev 			new_crtc_state->planes_changed,
4469b843c749SSergey Zigachev 			new_crtc_state->mode_changed,
4470b843c749SSergey Zigachev 			new_crtc_state->active_changed,
4471b843c749SSergey Zigachev 			new_crtc_state->connectors_changed);
4472b843c749SSergey Zigachev 
4473b843c749SSergey Zigachev 		/* Copy all transient state flags into dc state */
4474b843c749SSergey Zigachev 		if (dm_new_crtc_state->stream) {
4475b843c749SSergey Zigachev 			amdgpu_dm_crtc_copy_transient_flags(&dm_new_crtc_state->base,
4476b843c749SSergey Zigachev 							    dm_new_crtc_state->stream);
4477b843c749SSergey Zigachev 		}
4478b843c749SSergey Zigachev 
4479b843c749SSergey Zigachev 		/* handles headless hotplug case, updating new_state and
4480b843c749SSergey Zigachev 		 * aconnector as needed
4481b843c749SSergey Zigachev 		 */
4482b843c749SSergey Zigachev 
4483b843c749SSergey Zigachev 		if (modeset_required(new_crtc_state, dm_new_crtc_state->stream, dm_old_crtc_state->stream)) {
4484b843c749SSergey Zigachev 
4485b843c749SSergey Zigachev 			DRM_DEBUG_DRIVER("Atomic commit: SET crtc id %d: [%p]\n", acrtc->crtc_id, acrtc);
4486b843c749SSergey Zigachev 
4487b843c749SSergey Zigachev 			if (!dm_new_crtc_state->stream) {
4488b843c749SSergey Zigachev 				/*
4489b843c749SSergey Zigachev 				 * this could happen because of issues with
4490b843c749SSergey Zigachev 				 * userspace notifications delivery.
4491b843c749SSergey Zigachev 				 * In this case userspace tries to set mode on
4492b843c749SSergey Zigachev 				 * display which is disconnect in fact.
4493b843c749SSergey Zigachev 				 * dc_sink in NULL in this case on aconnector.
4494b843c749SSergey Zigachev 				 * We expect reset mode will come soon.
4495b843c749SSergey Zigachev 				 *
4496b843c749SSergey Zigachev 				 * This can also happen when unplug is done
4497b843c749SSergey Zigachev 				 * during resume sequence ended
4498b843c749SSergey Zigachev 				 *
4499b843c749SSergey Zigachev 				 * In this case, we want to pretend we still
4500b843c749SSergey Zigachev 				 * have a sink to keep the pipe running so that
4501b843c749SSergey Zigachev 				 * hw state is consistent with the sw state
4502b843c749SSergey Zigachev 				 */
4503b843c749SSergey Zigachev 				DRM_DEBUG_DRIVER("%s: Failed to create new stream for crtc %d\n",
4504b843c749SSergey Zigachev 						__func__, acrtc->base.base.id);
4505b843c749SSergey Zigachev 				continue;
4506b843c749SSergey Zigachev 			}
4507b843c749SSergey Zigachev 
4508b843c749SSergey Zigachev 			if (dm_old_crtc_state->stream)
4509b843c749SSergey Zigachev 				remove_stream(adev, acrtc, dm_old_crtc_state->stream);
4510*78973132SSergey Zigachev #if 0
4511b843c749SSergey Zigachev 			pm_runtime_get_noresume(dev->dev);
4512*78973132SSergey Zigachev #endif
4513b843c749SSergey Zigachev 
4514b843c749SSergey Zigachev 			acrtc->enabled = true;
4515b843c749SSergey Zigachev 			acrtc->hw_mode = new_crtc_state->mode;
4516b843c749SSergey Zigachev 			crtc->hwmode = new_crtc_state->mode;
4517b843c749SSergey Zigachev 		} else if (modereset_required(new_crtc_state)) {
4518b843c749SSergey Zigachev 			DRM_DEBUG_DRIVER("Atomic commit: RESET. crtc id %d:[%p]\n", acrtc->crtc_id, acrtc);
4519b843c749SSergey Zigachev 
4520b843c749SSergey Zigachev 			/* i.e. reset mode */
4521b843c749SSergey Zigachev 			if (dm_old_crtc_state->stream)
4522b843c749SSergey Zigachev 				remove_stream(adev, acrtc, dm_old_crtc_state->stream);
4523b843c749SSergey Zigachev 		}
4524b843c749SSergey Zigachev 	} /* for_each_crtc_in_state() */
4525b843c749SSergey Zigachev 
4526b843c749SSergey Zigachev 	/*
4527b843c749SSergey Zigachev 	 * Add streams after required streams from new and replaced streams
4528b843c749SSergey Zigachev 	 * are removed from freesync module
4529b843c749SSergey Zigachev 	 */
4530b843c749SSergey Zigachev 	if (adev->dm.freesync_module) {
4531b843c749SSergey Zigachev 		for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state,
4532b843c749SSergey Zigachev 					      new_crtc_state, i) {
4533b843c749SSergey Zigachev 			struct amdgpu_dm_connector *aconnector = NULL;
4534b843c749SSergey Zigachev 			struct dm_connector_state *dm_new_con_state = NULL;
4535b843c749SSergey Zigachev 			struct amdgpu_crtc *acrtc = NULL;
4536b843c749SSergey Zigachev 			bool modeset_needed;
4537b843c749SSergey Zigachev 
4538b843c749SSergey Zigachev 			dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
4539b843c749SSergey Zigachev 			dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
4540b843c749SSergey Zigachev 			modeset_needed = modeset_required(
4541b843c749SSergey Zigachev 					new_crtc_state,
4542b843c749SSergey Zigachev 					dm_new_crtc_state->stream,
4543b843c749SSergey Zigachev 					dm_old_crtc_state->stream);
4544b843c749SSergey Zigachev 			/* We add stream to freesync if:
4545b843c749SSergey Zigachev 			 * 1. Said stream is not null, and
4546b843c749SSergey Zigachev 			 * 2. A modeset is requested. This means that the
4547b843c749SSergey Zigachev 			 *    stream was removed previously, and needs to be
4548b843c749SSergey Zigachev 			 *    replaced.
4549b843c749SSergey Zigachev 			 */
4550b843c749SSergey Zigachev 			if (dm_new_crtc_state->stream == NULL ||
4551b843c749SSergey Zigachev 					!modeset_needed)
4552b843c749SSergey Zigachev 				continue;
4553b843c749SSergey Zigachev 
4554b843c749SSergey Zigachev 			acrtc = to_amdgpu_crtc(crtc);
4555b843c749SSergey Zigachev 
4556b843c749SSergey Zigachev 			aconnector =
4557b843c749SSergey Zigachev 				amdgpu_dm_find_first_crtc_matching_connector(
4558b843c749SSergey Zigachev 					state, crtc);
4559b843c749SSergey Zigachev 			if (!aconnector) {
4560b843c749SSergey Zigachev 				DRM_DEBUG_DRIVER("Atomic commit: Failed to "
4561b843c749SSergey Zigachev 						 "find connector for acrtc "
4562b843c749SSergey Zigachev 						 "id:%d skipping freesync "
4563b843c749SSergey Zigachev 						 "init\n",
4564b843c749SSergey Zigachev 						 acrtc->crtc_id);
4565b843c749SSergey Zigachev 				continue;
4566b843c749SSergey Zigachev 			}
4567b843c749SSergey Zigachev 
4568b843c749SSergey Zigachev 			mod_freesync_add_stream(adev->dm.freesync_module,
4569b843c749SSergey Zigachev 						dm_new_crtc_state->stream,
4570b843c749SSergey Zigachev 						&aconnector->caps);
4571b843c749SSergey Zigachev 			new_con_state = drm_atomic_get_new_connector_state(
4572b843c749SSergey Zigachev 					state, &aconnector->base);
4573b843c749SSergey Zigachev 			dm_new_con_state = to_dm_connector_state(new_con_state);
4574b843c749SSergey Zigachev 
4575b843c749SSergey Zigachev 			mod_freesync_set_user_enable(adev->dm.freesync_module,
4576b843c749SSergey Zigachev 						     &dm_new_crtc_state->stream,
4577b843c749SSergey Zigachev 						     1,
4578b843c749SSergey Zigachev 						     &dm_new_con_state->user_enable);
4579b843c749SSergey Zigachev 		}
4580b843c749SSergey Zigachev 	}
4581b843c749SSergey Zigachev 
4582b843c749SSergey Zigachev 	if (dm_state->context) {
4583b843c749SSergey Zigachev 		dm_enable_per_frame_crtc_master_sync(dm_state->context);
4584b843c749SSergey Zigachev 		WARN_ON(!dc_commit_state(dm->dc, dm_state->context));
4585b843c749SSergey Zigachev 	}
4586b843c749SSergey Zigachev 
4587b843c749SSergey Zigachev 	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
4588b843c749SSergey Zigachev 		struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
4589b843c749SSergey Zigachev 
4590b843c749SSergey Zigachev 		dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
4591b843c749SSergey Zigachev 
4592b843c749SSergey Zigachev 		if (dm_new_crtc_state->stream != NULL) {
4593b843c749SSergey Zigachev 			const struct dc_stream_status *status =
4594b843c749SSergey Zigachev 					dc_stream_get_status(dm_new_crtc_state->stream);
4595b843c749SSergey Zigachev 
4596b843c749SSergey Zigachev 			if (!status)
4597b843c749SSergey Zigachev 				DC_ERR("got no status for stream %p on acrtc%p\n", dm_new_crtc_state->stream, acrtc);
4598b843c749SSergey Zigachev 			else
4599b843c749SSergey Zigachev 				acrtc->otg_inst = status->primary_otg_inst;
4600b843c749SSergey Zigachev 		}
4601b843c749SSergey Zigachev 	}
4602b843c749SSergey Zigachev 
4603b843c749SSergey Zigachev 	/* Handle scaling and underscan changes*/
4604b843c749SSergey Zigachev 	for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
4605b843c749SSergey Zigachev 		struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state);
4606b843c749SSergey Zigachev 		struct dm_connector_state *dm_old_con_state = to_dm_connector_state(old_con_state);
4607b843c749SSergey Zigachev 		struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc);
4608b843c749SSergey Zigachev 		struct dc_stream_status *status = NULL;
4609b843c749SSergey Zigachev 
4610b843c749SSergey Zigachev 		if (acrtc) {
4611b843c749SSergey Zigachev 			new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base);
4612b843c749SSergey Zigachev 			old_crtc_state = drm_atomic_get_old_crtc_state(state, &acrtc->base);
4613b843c749SSergey Zigachev 		}
4614b843c749SSergey Zigachev 
4615b843c749SSergey Zigachev 		/* Skip any modesets/resets */
4616b843c749SSergey Zigachev 		if (!acrtc || drm_atomic_crtc_needs_modeset(new_crtc_state))
4617b843c749SSergey Zigachev 			continue;
4618b843c749SSergey Zigachev 
4619b843c749SSergey Zigachev 		/* Skip any thing not scale or underscan changes */
4620b843c749SSergey Zigachev 		if (!is_scaling_state_different(dm_new_con_state, dm_old_con_state))
4621b843c749SSergey Zigachev 			continue;
4622b843c749SSergey Zigachev 
4623b843c749SSergey Zigachev 		dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
4624b843c749SSergey Zigachev 
4625b843c749SSergey Zigachev 		update_stream_scaling_settings(&dm_new_con_state->base.crtc->mode,
4626b843c749SSergey Zigachev 				dm_new_con_state, (struct dc_stream_state *)dm_new_crtc_state->stream);
4627b843c749SSergey Zigachev 
4628b843c749SSergey Zigachev 		if (!dm_new_crtc_state->stream)
4629b843c749SSergey Zigachev 			continue;
4630b843c749SSergey Zigachev 
4631b843c749SSergey Zigachev 		status = dc_stream_get_status(dm_new_crtc_state->stream);
4632b843c749SSergey Zigachev 		WARN_ON(!status);
4633b843c749SSergey Zigachev 		WARN_ON(!status->plane_count);
4634b843c749SSergey Zigachev 
4635b843c749SSergey Zigachev 		/*TODO How it works with MPO ?*/
4636b843c749SSergey Zigachev 		if (!commit_planes_to_stream(
4637b843c749SSergey Zigachev 				dm->dc,
4638b843c749SSergey Zigachev 				status->plane_states,
4639b843c749SSergey Zigachev 				status->plane_count,
4640b843c749SSergey Zigachev 				dm_new_crtc_state,
4641b843c749SSergey Zigachev 				to_dm_crtc_state(old_crtc_state),
4642b843c749SSergey Zigachev 				dm_state->context))
4643b843c749SSergey Zigachev 			dm_error("%s: Failed to update stream scaling!\n", __func__);
4644b843c749SSergey Zigachev 	}
4645b843c749SSergey Zigachev 
4646b843c749SSergey Zigachev 	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state,
4647b843c749SSergey Zigachev 			new_crtc_state, i) {
4648b843c749SSergey Zigachev 		/*
4649b843c749SSergey Zigachev 		 * loop to enable interrupts on newly arrived crtc
4650b843c749SSergey Zigachev 		 */
4651b843c749SSergey Zigachev 		struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
4652b843c749SSergey Zigachev 		bool modeset_needed;
4653b843c749SSergey Zigachev 
4654b843c749SSergey Zigachev 		if (old_crtc_state->active && !new_crtc_state->active)
4655b843c749SSergey Zigachev 			crtc_disable_count++;
4656b843c749SSergey Zigachev 
4657b843c749SSergey Zigachev 		dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
4658b843c749SSergey Zigachev 		dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
4659b843c749SSergey Zigachev 		modeset_needed = modeset_required(
4660b843c749SSergey Zigachev 				new_crtc_state,
4661b843c749SSergey Zigachev 				dm_new_crtc_state->stream,
4662b843c749SSergey Zigachev 				dm_old_crtc_state->stream);
4663b843c749SSergey Zigachev 
4664b843c749SSergey Zigachev 		if (dm_new_crtc_state->stream == NULL || !modeset_needed)
4665b843c749SSergey Zigachev 			continue;
4666b843c749SSergey Zigachev 
4667b843c749SSergey Zigachev 		if (adev->dm.freesync_module)
4668b843c749SSergey Zigachev 			mod_freesync_notify_mode_change(
4669b843c749SSergey Zigachev 				adev->dm.freesync_module,
4670b843c749SSergey Zigachev 				&dm_new_crtc_state->stream, 1);
4671b843c749SSergey Zigachev 
4672b843c749SSergey Zigachev 		manage_dm_interrupts(adev, acrtc, true);
4673b843c749SSergey Zigachev 	}
4674b843c749SSergey Zigachev 
4675b843c749SSergey Zigachev 	/* update planes when needed per crtc*/
4676b843c749SSergey Zigachev 	for_each_new_crtc_in_state(state, crtc, new_crtc_state, j) {
4677b843c749SSergey Zigachev 		dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
4678b843c749SSergey Zigachev 
4679b843c749SSergey Zigachev 		if (dm_new_crtc_state->stream)
4680b843c749SSergey Zigachev 			amdgpu_dm_commit_planes(state, dev, dm, crtc, &wait_for_vblank);
4681b843c749SSergey Zigachev 	}
4682b843c749SSergey Zigachev 
4683b843c749SSergey Zigachev 
4684b843c749SSergey Zigachev 	/*
4685b843c749SSergey Zigachev 	 * send vblank event on all events not handled in flip and
4686b843c749SSergey Zigachev 	 * mark consumed event for drm_atomic_helper_commit_hw_done
4687b843c749SSergey Zigachev 	 */
4688b843c749SSergey Zigachev 	spin_lock_irqsave(&adev->ddev->event_lock, flags);
4689b843c749SSergey Zigachev 	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
4690b843c749SSergey Zigachev 
4691b843c749SSergey Zigachev 		if (new_crtc_state->event)
4692b843c749SSergey Zigachev 			drm_send_event_locked(dev, &new_crtc_state->event->base);
4693b843c749SSergey Zigachev 
4694b843c749SSergey Zigachev 		new_crtc_state->event = NULL;
4695b843c749SSergey Zigachev 	}
4696b843c749SSergey Zigachev 	spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
4697b843c749SSergey Zigachev 
4698b843c749SSergey Zigachev 
4699b843c749SSergey Zigachev 	if (wait_for_vblank)
4700b843c749SSergey Zigachev 		drm_atomic_helper_wait_for_flip_done(dev, state);
4701b843c749SSergey Zigachev 
4702b843c749SSergey Zigachev 	/*
4703b843c749SSergey Zigachev 	 * FIXME:
4704b843c749SSergey Zigachev 	 * Delay hw_done() until flip_done() is signaled. This is to block
4705b843c749SSergey Zigachev 	 * another commit from freeing the CRTC state while we're still
4706b843c749SSergey Zigachev 	 * waiting on flip_done.
4707b843c749SSergey Zigachev 	 */
4708b843c749SSergey Zigachev 	drm_atomic_helper_commit_hw_done(state);
4709b843c749SSergey Zigachev 
4710b843c749SSergey Zigachev 	drm_atomic_helper_cleanup_planes(dev, state);
4711b843c749SSergey Zigachev 
4712b843c749SSergey Zigachev 	/* Finally, drop a runtime PM reference for each newly disabled CRTC,
4713b843c749SSergey Zigachev 	 * so we can put the GPU into runtime suspend if we're not driving any
4714b843c749SSergey Zigachev 	 * displays anymore
4715b843c749SSergey Zigachev 	 */
4716b843c749SSergey Zigachev 	for (i = 0; i < crtc_disable_count; i++)
4717b843c749SSergey Zigachev 		pm_runtime_put_autosuspend(dev->dev);
4718b843c749SSergey Zigachev 	pm_runtime_mark_last_busy(dev->dev);
4719b843c749SSergey Zigachev }
4720b843c749SSergey Zigachev 
4721b843c749SSergey Zigachev 
dm_force_atomic_commit(struct drm_connector * connector)4722b843c749SSergey Zigachev static int dm_force_atomic_commit(struct drm_connector *connector)
4723b843c749SSergey Zigachev {
4724b843c749SSergey Zigachev 	int ret = 0;
4725b843c749SSergey Zigachev 	struct drm_device *ddev = connector->dev;
4726b843c749SSergey Zigachev 	struct drm_atomic_state *state = drm_atomic_state_alloc(ddev);
4727b843c749SSergey Zigachev 	struct amdgpu_crtc *disconnected_acrtc = to_amdgpu_crtc(connector->encoder->crtc);
4728b843c749SSergey Zigachev 	struct drm_plane *plane = disconnected_acrtc->base.primary;
4729b843c749SSergey Zigachev 	struct drm_connector_state *conn_state;
4730b843c749SSergey Zigachev 	struct drm_crtc_state *crtc_state;
4731b843c749SSergey Zigachev 	struct drm_plane_state *plane_state;
4732b843c749SSergey Zigachev 
4733b843c749SSergey Zigachev 	if (!state)
4734b843c749SSergey Zigachev 		return -ENOMEM;
4735b843c749SSergey Zigachev 
4736b843c749SSergey Zigachev 	state->acquire_ctx = ddev->mode_config.acquire_ctx;
4737b843c749SSergey Zigachev 
4738b843c749SSergey Zigachev 	/* Construct an atomic state to restore previous display setting */
4739b843c749SSergey Zigachev 
4740b843c749SSergey Zigachev 	/*
4741b843c749SSergey Zigachev 	 * Attach connectors to drm_atomic_state
4742b843c749SSergey Zigachev 	 */
4743b843c749SSergey Zigachev 	conn_state = drm_atomic_get_connector_state(state, connector);
4744b843c749SSergey Zigachev 
4745b843c749SSergey Zigachev 	ret = PTR_ERR_OR_ZERO(conn_state);
4746b843c749SSergey Zigachev 	if (ret)
4747b843c749SSergey Zigachev 		goto out;
4748b843c749SSergey Zigachev 
4749b843c749SSergey Zigachev 	/* Attach crtc to drm_atomic_state*/
4750b843c749SSergey Zigachev 	crtc_state = drm_atomic_get_crtc_state(state, &disconnected_acrtc->base);
4751b843c749SSergey Zigachev 
4752b843c749SSergey Zigachev 	ret = PTR_ERR_OR_ZERO(crtc_state);
4753b843c749SSergey Zigachev 	if (ret)
4754b843c749SSergey Zigachev 		goto out;
4755b843c749SSergey Zigachev 
4756b843c749SSergey Zigachev 	/* force a restore */
4757b843c749SSergey Zigachev 	crtc_state->mode_changed = true;
4758b843c749SSergey Zigachev 
4759b843c749SSergey Zigachev 	/* Attach plane to drm_atomic_state */
4760b843c749SSergey Zigachev 	plane_state = drm_atomic_get_plane_state(state, plane);
4761b843c749SSergey Zigachev 
4762b843c749SSergey Zigachev 	ret = PTR_ERR_OR_ZERO(plane_state);
4763b843c749SSergey Zigachev 	if (ret)
4764b843c749SSergey Zigachev 		goto out;
4765b843c749SSergey Zigachev 
4766b843c749SSergey Zigachev 	/* Call commit internally with the state we just constructed */
4767b843c749SSergey Zigachev 	ret = drm_atomic_commit(state);
4768b843c749SSergey Zigachev 
4769b843c749SSergey Zigachev out:
4770b843c749SSergey Zigachev 	drm_atomic_state_put(state);
4771b843c749SSergey Zigachev 	if (ret)
4772b843c749SSergey Zigachev 		DRM_ERROR("Restoring old state failed with %i\n", ret);
4773b843c749SSergey Zigachev 
4774b843c749SSergey Zigachev 	return ret;
4775b843c749SSergey Zigachev }
4776b843c749SSergey Zigachev 
4777b843c749SSergey Zigachev /*
4778b843c749SSergey Zigachev  * This functions handle all cases when set mode does not come upon hotplug.
4779b843c749SSergey Zigachev  * This include when the same display is unplugged then plugged back into the
4780b843c749SSergey Zigachev  * same port and when we are running without usermode desktop manager supprot
4781b843c749SSergey Zigachev  */
dm_restore_drm_connector_state(struct drm_device * dev,struct drm_connector * connector)4782b843c749SSergey Zigachev void dm_restore_drm_connector_state(struct drm_device *dev,
4783b843c749SSergey Zigachev 				    struct drm_connector *connector)
4784b843c749SSergey Zigachev {
4785b843c749SSergey Zigachev 	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
4786b843c749SSergey Zigachev 	struct amdgpu_crtc *disconnected_acrtc;
4787b843c749SSergey Zigachev 	struct dm_crtc_state *acrtc_state;
4788b843c749SSergey Zigachev 
4789b843c749SSergey Zigachev 	if (!aconnector->dc_sink || !connector->state || !connector->encoder)
4790b843c749SSergey Zigachev 		return;
4791b843c749SSergey Zigachev 
4792b843c749SSergey Zigachev 	disconnected_acrtc = to_amdgpu_crtc(connector->encoder->crtc);
4793b843c749SSergey Zigachev 	if (!disconnected_acrtc)
4794b843c749SSergey Zigachev 		return;
4795b843c749SSergey Zigachev 
4796b843c749SSergey Zigachev 	acrtc_state = to_dm_crtc_state(disconnected_acrtc->base.state);
4797b843c749SSergey Zigachev 	if (!acrtc_state->stream)
4798b843c749SSergey Zigachev 		return;
4799b843c749SSergey Zigachev 
4800b843c749SSergey Zigachev 	/*
4801b843c749SSergey Zigachev 	 * If the previous sink is not released and different from the current,
4802b843c749SSergey Zigachev 	 * we deduce we are in a state where we can not rely on usermode call
4803b843c749SSergey Zigachev 	 * to turn on the display, so we do it here
4804b843c749SSergey Zigachev 	 */
4805b843c749SSergey Zigachev 	if (acrtc_state->stream->sink != aconnector->dc_sink)
4806b843c749SSergey Zigachev 		dm_force_atomic_commit(&aconnector->base);
4807b843c749SSergey Zigachev }
4808b843c749SSergey Zigachev 
4809b843c749SSergey Zigachev /*`
4810b843c749SSergey Zigachev  * Grabs all modesetting locks to serialize against any blocking commits,
4811b843c749SSergey Zigachev  * Waits for completion of all non blocking commits.
4812b843c749SSergey Zigachev  */
do_aquire_global_lock(struct drm_device * dev,struct drm_atomic_state * state)4813b843c749SSergey Zigachev static int do_aquire_global_lock(struct drm_device *dev,
4814b843c749SSergey Zigachev 				 struct drm_atomic_state *state)
4815b843c749SSergey Zigachev {
4816b843c749SSergey Zigachev 	struct drm_crtc *crtc;
4817b843c749SSergey Zigachev 	struct drm_crtc_commit *commit;
4818b843c749SSergey Zigachev 	long ret;
4819b843c749SSergey Zigachev 
4820b843c749SSergey Zigachev 	/* Adding all modeset locks to aquire_ctx will
4821b843c749SSergey Zigachev 	 * ensure that when the framework release it the
4822b843c749SSergey Zigachev 	 * extra locks we are locking here will get released to
4823b843c749SSergey Zigachev 	 */
4824b843c749SSergey Zigachev 	ret = drm_modeset_lock_all_ctx(dev, state->acquire_ctx);
4825b843c749SSergey Zigachev 	if (ret)
4826b843c749SSergey Zigachev 		return ret;
4827b843c749SSergey Zigachev 
4828b843c749SSergey Zigachev 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
4829*78973132SSergey Zigachev 		lockmgr(&crtc->commit_lock, LK_EXCLUSIVE);
4830b843c749SSergey Zigachev 		commit = list_first_entry_or_null(&crtc->commit_list,
4831b843c749SSergey Zigachev 				struct drm_crtc_commit, commit_entry);
4832b843c749SSergey Zigachev 		if (commit)
4833b843c749SSergey Zigachev 			drm_crtc_commit_get(commit);
4834*78973132SSergey Zigachev 		lockmgr(&crtc->commit_lock, LK_RELEASE);
4835b843c749SSergey Zigachev 
4836b843c749SSergey Zigachev 		if (!commit)
4837b843c749SSergey Zigachev 			continue;
4838b843c749SSergey Zigachev 
4839b843c749SSergey Zigachev 		/* Make sure all pending HW programming completed and
4840b843c749SSergey Zigachev 		 * page flips done
4841b843c749SSergey Zigachev 		 */
4842b843c749SSergey Zigachev 		ret = wait_for_completion_interruptible_timeout(&commit->hw_done, 10*HZ);
4843b843c749SSergey Zigachev 
4844b843c749SSergey Zigachev 		if (ret > 0)
4845b843c749SSergey Zigachev 			ret = wait_for_completion_interruptible_timeout(
4846b843c749SSergey Zigachev 					&commit->flip_done, 10*HZ);
4847b843c749SSergey Zigachev 
4848b843c749SSergey Zigachev 		if (ret == 0)
4849b843c749SSergey Zigachev 			DRM_ERROR("[CRTC:%d:%s] hw_done or flip_done "
4850b843c749SSergey Zigachev 				  "timed out\n", crtc->base.id, crtc->name);
4851b843c749SSergey Zigachev 
4852b843c749SSergey Zigachev 		drm_crtc_commit_put(commit);
4853b843c749SSergey Zigachev 	}
4854b843c749SSergey Zigachev 
4855b843c749SSergey Zigachev 	return ret < 0 ? ret : 0;
4856b843c749SSergey Zigachev }
4857b843c749SSergey Zigachev 
dm_update_crtcs_state(struct dc * dc,struct drm_atomic_state * state,bool enable,bool * lock_and_validation_needed)4858b843c749SSergey Zigachev static int dm_update_crtcs_state(struct dc *dc,
4859b843c749SSergey Zigachev 				 struct drm_atomic_state *state,
4860b843c749SSergey Zigachev 				 bool enable,
4861b843c749SSergey Zigachev 				 bool *lock_and_validation_needed)
4862b843c749SSergey Zigachev {
4863b843c749SSergey Zigachev 	struct drm_crtc *crtc;
4864b843c749SSergey Zigachev 	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
4865b843c749SSergey Zigachev 	int i;
4866b843c749SSergey Zigachev 	struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
4867b843c749SSergey Zigachev 	struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
4868b843c749SSergey Zigachev 	struct dc_stream_state *new_stream;
4869b843c749SSergey Zigachev 	int ret = 0;
4870b843c749SSergey Zigachev 
4871b843c749SSergey Zigachev 	/*TODO Move this code into dm_crtc_atomic_check once we get rid of dc_validation_set */
4872b843c749SSergey Zigachev 	/* update changed items */
4873b843c749SSergey Zigachev 	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
4874b843c749SSergey Zigachev 		struct amdgpu_crtc *acrtc = NULL;
4875b843c749SSergey Zigachev 		struct amdgpu_dm_connector *aconnector = NULL;
4876b843c749SSergey Zigachev 		struct drm_connector_state *drm_new_conn_state = NULL, *drm_old_conn_state = NULL;
4877b843c749SSergey Zigachev 		struct dm_connector_state *dm_new_conn_state = NULL, *dm_old_conn_state = NULL;
4878b843c749SSergey Zigachev 		struct drm_plane_state *new_plane_state = NULL;
4879b843c749SSergey Zigachev 
4880b843c749SSergey Zigachev 		new_stream = NULL;
4881b843c749SSergey Zigachev 
4882b843c749SSergey Zigachev 		dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
4883b843c749SSergey Zigachev 		dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
4884b843c749SSergey Zigachev 		acrtc = to_amdgpu_crtc(crtc);
4885b843c749SSergey Zigachev 
4886b843c749SSergey Zigachev 		new_plane_state = drm_atomic_get_new_plane_state(state, new_crtc_state->crtc->primary);
4887b843c749SSergey Zigachev 
4888b843c749SSergey Zigachev 		if (new_crtc_state->enable && new_plane_state && !new_plane_state->fb) {
4889b843c749SSergey Zigachev 			ret = -EINVAL;
4890b843c749SSergey Zigachev 			goto fail;
4891b843c749SSergey Zigachev 		}
4892b843c749SSergey Zigachev 
4893b843c749SSergey Zigachev 		aconnector = amdgpu_dm_find_first_crtc_matching_connector(state, crtc);
4894b843c749SSergey Zigachev 
4895b843c749SSergey Zigachev 		/* TODO This hack should go away */
4896b843c749SSergey Zigachev 		if (aconnector && enable) {
4897b843c749SSergey Zigachev 			// Make sure fake sink is created in plug-in scenario
4898b843c749SSergey Zigachev 			drm_new_conn_state = drm_atomic_get_new_connector_state(state,
4899b843c749SSergey Zigachev  								    &aconnector->base);
4900b843c749SSergey Zigachev 			drm_old_conn_state = drm_atomic_get_old_connector_state(state,
4901b843c749SSergey Zigachev 								    &aconnector->base);
4902b843c749SSergey Zigachev 
4903b843c749SSergey Zigachev 			if (IS_ERR(drm_new_conn_state)) {
4904b843c749SSergey Zigachev 				ret = PTR_ERR_OR_ZERO(drm_new_conn_state);
4905b843c749SSergey Zigachev 				break;
4906b843c749SSergey Zigachev 			}
4907b843c749SSergey Zigachev 
4908b843c749SSergey Zigachev 			dm_new_conn_state = to_dm_connector_state(drm_new_conn_state);
4909b843c749SSergey Zigachev 			dm_old_conn_state = to_dm_connector_state(drm_old_conn_state);
4910b843c749SSergey Zigachev 
4911b843c749SSergey Zigachev 			new_stream = create_stream_for_sink(aconnector,
4912b843c749SSergey Zigachev 							     &new_crtc_state->mode,
4913b843c749SSergey Zigachev 							    dm_new_conn_state);
4914b843c749SSergey Zigachev 
4915b843c749SSergey Zigachev 			/*
4916b843c749SSergey Zigachev 			 * we can have no stream on ACTION_SET if a display
4917b843c749SSergey Zigachev 			 * was disconnected during S3, in this case it not and
4918b843c749SSergey Zigachev 			 * error, the OS will be updated after detection, and
4919b843c749SSergey Zigachev 			 * do the right thing on next atomic commit
4920b843c749SSergey Zigachev 			 */
4921b843c749SSergey Zigachev 
4922b843c749SSergey Zigachev 			if (!new_stream) {
4923b843c749SSergey Zigachev 				DRM_DEBUG_DRIVER("%s: Failed to create new stream for crtc %d\n",
4924b843c749SSergey Zigachev 						__func__, acrtc->base.base.id);
4925b843c749SSergey Zigachev 				break;
4926b843c749SSergey Zigachev 			}
4927b843c749SSergey Zigachev 
4928b843c749SSergey Zigachev 			if (dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) &&
4929b843c749SSergey Zigachev 			    dc_is_stream_scaling_unchanged(new_stream, dm_old_crtc_state->stream)) {
4930b843c749SSergey Zigachev 				new_crtc_state->mode_changed = false;
4931b843c749SSergey Zigachev 				DRM_DEBUG_DRIVER("Mode change not required, setting mode_changed to %d",
4932b843c749SSergey Zigachev 						 new_crtc_state->mode_changed);
4933b843c749SSergey Zigachev 			}
4934b843c749SSergey Zigachev 		}
4935b843c749SSergey Zigachev 
4936b843c749SSergey Zigachev 		if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
4937b843c749SSergey Zigachev 			goto next_crtc;
4938b843c749SSergey Zigachev 
4939b843c749SSergey Zigachev 		DRM_DEBUG_DRIVER(
4940b843c749SSergey Zigachev 			"amdgpu_crtc id:%d crtc_state_flags: enable:%d, active:%d, "
4941b843c749SSergey Zigachev 			"planes_changed:%d, mode_changed:%d,active_changed:%d,"
4942b843c749SSergey Zigachev 			"connectors_changed:%d\n",
4943b843c749SSergey Zigachev 			acrtc->crtc_id,
4944b843c749SSergey Zigachev 			new_crtc_state->enable,
4945b843c749SSergey Zigachev 			new_crtc_state->active,
4946b843c749SSergey Zigachev 			new_crtc_state->planes_changed,
4947b843c749SSergey Zigachev 			new_crtc_state->mode_changed,
4948b843c749SSergey Zigachev 			new_crtc_state->active_changed,
4949b843c749SSergey Zigachev 			new_crtc_state->connectors_changed);
4950b843c749SSergey Zigachev 
4951b843c749SSergey Zigachev 		/* Remove stream for any changed/disabled CRTC */
4952b843c749SSergey Zigachev 		if (!enable) {
4953b843c749SSergey Zigachev 
4954b843c749SSergey Zigachev 			if (!dm_old_crtc_state->stream)
4955b843c749SSergey Zigachev 				goto next_crtc;
4956b843c749SSergey Zigachev 
4957b843c749SSergey Zigachev 			DRM_DEBUG_DRIVER("Disabling DRM crtc: %d\n",
4958b843c749SSergey Zigachev 					crtc->base.id);
4959b843c749SSergey Zigachev 
4960b843c749SSergey Zigachev 			/* i.e. reset mode */
4961b843c749SSergey Zigachev 			if (dc_remove_stream_from_ctx(
4962b843c749SSergey Zigachev 					dc,
4963b843c749SSergey Zigachev 					dm_state->context,
4964b843c749SSergey Zigachev 					dm_old_crtc_state->stream) != DC_OK) {
4965b843c749SSergey Zigachev 				ret = -EINVAL;
4966b843c749SSergey Zigachev 				goto fail;
4967b843c749SSergey Zigachev 			}
4968b843c749SSergey Zigachev 
4969b843c749SSergey Zigachev 			dc_stream_release(dm_old_crtc_state->stream);
4970b843c749SSergey Zigachev 			dm_new_crtc_state->stream = NULL;
4971b843c749SSergey Zigachev 
4972b843c749SSergey Zigachev 			*lock_and_validation_needed = true;
4973b843c749SSergey Zigachev 
4974b843c749SSergey Zigachev 		} else {/* Add stream for any updated/enabled CRTC */
4975b843c749SSergey Zigachev 			/*
4976b843c749SSergey Zigachev 			 * Quick fix to prevent NULL pointer on new_stream when
4977b843c749SSergey Zigachev 			 * added MST connectors not found in existing crtc_state in the chained mode
4978b843c749SSergey Zigachev 			 * TODO: need to dig out the root cause of that
4979b843c749SSergey Zigachev 			 */
4980b843c749SSergey Zigachev 			if (!aconnector || (!aconnector->dc_sink && aconnector->mst_port))
4981b843c749SSergey Zigachev 				goto next_crtc;
4982b843c749SSergey Zigachev 
4983b843c749SSergey Zigachev 			if (modereset_required(new_crtc_state))
4984b843c749SSergey Zigachev 				goto next_crtc;
4985b843c749SSergey Zigachev 
4986b843c749SSergey Zigachev 			if (modeset_required(new_crtc_state, new_stream,
4987b843c749SSergey Zigachev 					     dm_old_crtc_state->stream)) {
4988b843c749SSergey Zigachev 
4989b843c749SSergey Zigachev 				WARN_ON(dm_new_crtc_state->stream);
4990b843c749SSergey Zigachev 
4991b843c749SSergey Zigachev 				dm_new_crtc_state->stream = new_stream;
4992b843c749SSergey Zigachev 
4993b843c749SSergey Zigachev 				dc_stream_retain(new_stream);
4994b843c749SSergey Zigachev 
4995b843c749SSergey Zigachev 				DRM_DEBUG_DRIVER("Enabling DRM crtc: %d\n",
4996b843c749SSergey Zigachev 							crtc->base.id);
4997b843c749SSergey Zigachev 
4998b843c749SSergey Zigachev 				if (dc_add_stream_to_ctx(
4999b843c749SSergey Zigachev 						dc,
5000b843c749SSergey Zigachev 						dm_state->context,
5001b843c749SSergey Zigachev 						dm_new_crtc_state->stream) != DC_OK) {
5002b843c749SSergey Zigachev 					ret = -EINVAL;
5003b843c749SSergey Zigachev 					goto fail;
5004b843c749SSergey Zigachev 				}
5005b843c749SSergey Zigachev 
5006b843c749SSergey Zigachev 				*lock_and_validation_needed = true;
5007b843c749SSergey Zigachev 			}
5008b843c749SSergey Zigachev 		}
5009b843c749SSergey Zigachev 
5010b843c749SSergey Zigachev next_crtc:
5011b843c749SSergey Zigachev 		/* Release extra reference */
5012b843c749SSergey Zigachev 		if (new_stream)
5013b843c749SSergey Zigachev 			 dc_stream_release(new_stream);
5014b843c749SSergey Zigachev 
5015b843c749SSergey Zigachev 		/*
5016b843c749SSergey Zigachev 		 * We want to do dc stream updates that do not require a
5017b843c749SSergey Zigachev 		 * full modeset below.
5018b843c749SSergey Zigachev 		 */
5019b843c749SSergey Zigachev 		if (!(enable && aconnector && new_crtc_state->enable &&
5020b843c749SSergey Zigachev 		      new_crtc_state->active))
5021b843c749SSergey Zigachev 			continue;
5022b843c749SSergey Zigachev 		/*
5023b843c749SSergey Zigachev 		 * Given above conditions, the dc state cannot be NULL because:
5024b843c749SSergey Zigachev 		 * 1. We're in the process of enabling CRTCs (just been added
5025b843c749SSergey Zigachev 		 *    to the dc context, or already is on the context)
5026b843c749SSergey Zigachev 		 * 2. Has a valid connector attached, and
5027b843c749SSergey Zigachev 		 * 3. Is currently active and enabled.
5028b843c749SSergey Zigachev 		 * => The dc stream state currently exists.
5029b843c749SSergey Zigachev 		 */
5030b843c749SSergey Zigachev 		BUG_ON(dm_new_crtc_state->stream == NULL);
5031b843c749SSergey Zigachev 
5032b843c749SSergey Zigachev 		/* Scaling or underscan settings */
5033b843c749SSergey Zigachev 		if (is_scaling_state_different(dm_old_conn_state, dm_new_conn_state))
5034b843c749SSergey Zigachev 			update_stream_scaling_settings(
5035b843c749SSergey Zigachev 				&new_crtc_state->mode, dm_new_conn_state, dm_new_crtc_state->stream);
5036b843c749SSergey Zigachev 
5037b843c749SSergey Zigachev 		/*
5038b843c749SSergey Zigachev 		 * Color management settings. We also update color properties
5039b843c749SSergey Zigachev 		 * when a modeset is needed, to ensure it gets reprogrammed.
5040b843c749SSergey Zigachev 		 */
5041b843c749SSergey Zigachev 		if (dm_new_crtc_state->base.color_mgmt_changed ||
5042b843c749SSergey Zigachev 		    drm_atomic_crtc_needs_modeset(new_crtc_state)) {
5043b843c749SSergey Zigachev 			ret = amdgpu_dm_set_regamma_lut(dm_new_crtc_state);
5044b843c749SSergey Zigachev 			if (ret)
5045b843c749SSergey Zigachev 				goto fail;
5046b843c749SSergey Zigachev 			amdgpu_dm_set_ctm(dm_new_crtc_state);
5047b843c749SSergey Zigachev 		}
5048b843c749SSergey Zigachev 	}
5049b843c749SSergey Zigachev 
5050b843c749SSergey Zigachev 	return ret;
5051b843c749SSergey Zigachev 
5052b843c749SSergey Zigachev fail:
5053b843c749SSergey Zigachev 	if (new_stream)
5054b843c749SSergey Zigachev 		dc_stream_release(new_stream);
5055b843c749SSergey Zigachev 	return ret;
5056b843c749SSergey Zigachev }
5057b843c749SSergey Zigachev 
dm_update_planes_state(struct dc * dc,struct drm_atomic_state * state,bool enable,bool * lock_and_validation_needed)5058b843c749SSergey Zigachev static int dm_update_planes_state(struct dc *dc,
5059b843c749SSergey Zigachev 				  struct drm_atomic_state *state,
5060b843c749SSergey Zigachev 				  bool enable,
5061b843c749SSergey Zigachev 				  bool *lock_and_validation_needed)
5062b843c749SSergey Zigachev {
5063b843c749SSergey Zigachev 	struct drm_crtc *new_plane_crtc, *old_plane_crtc;
5064b843c749SSergey Zigachev 	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
5065b843c749SSergey Zigachev 	struct drm_plane *plane;
5066b843c749SSergey Zigachev 	struct drm_plane_state *old_plane_state, *new_plane_state;
5067b843c749SSergey Zigachev 	struct dm_crtc_state *dm_new_crtc_state, *dm_old_crtc_state;
5068b843c749SSergey Zigachev 	struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
5069b843c749SSergey Zigachev 	struct dm_plane_state *dm_new_plane_state, *dm_old_plane_state;
5070b843c749SSergey Zigachev 	int i ;
5071b843c749SSergey Zigachev 	/* TODO return page_flip_needed() function */
5072b843c749SSergey Zigachev 	bool pflip_needed  = !state->allow_modeset;
5073b843c749SSergey Zigachev 	int ret = 0;
5074b843c749SSergey Zigachev 
5075b843c749SSergey Zigachev 
5076b843c749SSergey Zigachev 	/* Add new planes, in reverse order as DC expectation */
5077b843c749SSergey Zigachev 	for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) {
5078b843c749SSergey Zigachev 		new_plane_crtc = new_plane_state->crtc;
5079b843c749SSergey Zigachev 		old_plane_crtc = old_plane_state->crtc;
5080b843c749SSergey Zigachev 		dm_new_plane_state = to_dm_plane_state(new_plane_state);
5081b843c749SSergey Zigachev 		dm_old_plane_state = to_dm_plane_state(old_plane_state);
5082b843c749SSergey Zigachev 
5083b843c749SSergey Zigachev 		/*TODO Implement atomic check for cursor plane */
5084b843c749SSergey Zigachev 		if (plane->type == DRM_PLANE_TYPE_CURSOR)
5085b843c749SSergey Zigachev 			continue;
5086b843c749SSergey Zigachev 
5087b843c749SSergey Zigachev 		/* Remove any changed/removed planes */
5088b843c749SSergey Zigachev 		if (!enable) {
5089b843c749SSergey Zigachev 			if (pflip_needed &&
5090b843c749SSergey Zigachev 			    plane->type != DRM_PLANE_TYPE_OVERLAY)
5091b843c749SSergey Zigachev 				continue;
5092b843c749SSergey Zigachev 
5093b843c749SSergey Zigachev 			if (!old_plane_crtc)
5094b843c749SSergey Zigachev 				continue;
5095b843c749SSergey Zigachev 
5096b843c749SSergey Zigachev 			old_crtc_state = drm_atomic_get_old_crtc_state(
5097b843c749SSergey Zigachev 					state, old_plane_crtc);
5098b843c749SSergey Zigachev 			dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
5099b843c749SSergey Zigachev 
5100b843c749SSergey Zigachev 			if (!dm_old_crtc_state->stream)
5101b843c749SSergey Zigachev 				continue;
5102b843c749SSergey Zigachev 
5103b843c749SSergey Zigachev 			DRM_DEBUG_ATOMIC("Disabling DRM plane: %d on DRM crtc %d\n",
5104b843c749SSergey Zigachev 					plane->base.id, old_plane_crtc->base.id);
5105b843c749SSergey Zigachev 
5106b843c749SSergey Zigachev 			if (!dc_remove_plane_from_context(
5107b843c749SSergey Zigachev 					dc,
5108b843c749SSergey Zigachev 					dm_old_crtc_state->stream,
5109b843c749SSergey Zigachev 					dm_old_plane_state->dc_state,
5110b843c749SSergey Zigachev 					dm_state->context)) {
5111b843c749SSergey Zigachev 
5112b843c749SSergey Zigachev 				ret = EINVAL;
5113b843c749SSergey Zigachev 				return ret;
5114b843c749SSergey Zigachev 			}
5115b843c749SSergey Zigachev 
5116b843c749SSergey Zigachev 
5117b843c749SSergey Zigachev 			dc_plane_state_release(dm_old_plane_state->dc_state);
5118b843c749SSergey Zigachev 			dm_new_plane_state->dc_state = NULL;
5119b843c749SSergey Zigachev 
5120b843c749SSergey Zigachev 			*lock_and_validation_needed = true;
5121b843c749SSergey Zigachev 
5122b843c749SSergey Zigachev 		} else { /* Add new planes */
5123b843c749SSergey Zigachev 			struct dc_plane_state *dc_new_plane_state;
5124b843c749SSergey Zigachev 
5125b843c749SSergey Zigachev 			if (drm_atomic_plane_disabling(plane->state, new_plane_state))
5126b843c749SSergey Zigachev 				continue;
5127b843c749SSergey Zigachev 
5128b843c749SSergey Zigachev 			if (!new_plane_crtc)
5129b843c749SSergey Zigachev 				continue;
5130b843c749SSergey Zigachev 
5131b843c749SSergey Zigachev 			new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_crtc);
5132b843c749SSergey Zigachev 			dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
5133b843c749SSergey Zigachev 
5134b843c749SSergey Zigachev 			if (!dm_new_crtc_state->stream)
5135b843c749SSergey Zigachev 				continue;
5136b843c749SSergey Zigachev 
5137b843c749SSergey Zigachev 			if (pflip_needed &&
5138b843c749SSergey Zigachev 			    plane->type != DRM_PLANE_TYPE_OVERLAY)
5139b843c749SSergey Zigachev 				continue;
5140b843c749SSergey Zigachev 
5141b843c749SSergey Zigachev 			WARN_ON(dm_new_plane_state->dc_state);
5142b843c749SSergey Zigachev 
5143b843c749SSergey Zigachev 			dc_new_plane_state = dc_create_plane_state(dc);
5144b843c749SSergey Zigachev 			if (!dc_new_plane_state)
5145b843c749SSergey Zigachev 				return -ENOMEM;
5146b843c749SSergey Zigachev 
5147b843c749SSergey Zigachev 			DRM_DEBUG_DRIVER("Enabling DRM plane: %d on DRM crtc %d\n",
5148b843c749SSergey Zigachev 					plane->base.id, new_plane_crtc->base.id);
5149b843c749SSergey Zigachev 
5150b843c749SSergey Zigachev 			ret = fill_plane_attributes(
5151b843c749SSergey Zigachev 				new_plane_crtc->dev->dev_private,
5152b843c749SSergey Zigachev 				dc_new_plane_state,
5153b843c749SSergey Zigachev 				new_plane_state,
5154b843c749SSergey Zigachev 				new_crtc_state);
5155b843c749SSergey Zigachev 			if (ret) {
5156b843c749SSergey Zigachev 				dc_plane_state_release(dc_new_plane_state);
5157b843c749SSergey Zigachev 				return ret;
5158b843c749SSergey Zigachev 			}
5159b843c749SSergey Zigachev 
5160b843c749SSergey Zigachev 			/*
5161b843c749SSergey Zigachev 			 * Any atomic check errors that occur after this will
5162b843c749SSergey Zigachev 			 * not need a release. The plane state will be attached
5163b843c749SSergey Zigachev 			 * to the stream, and therefore part of the atomic
5164b843c749SSergey Zigachev 			 * state. It'll be released when the atomic state is
5165b843c749SSergey Zigachev 			 * cleaned.
5166b843c749SSergey Zigachev 			 */
5167b843c749SSergey Zigachev 			if (!dc_add_plane_to_context(
5168b843c749SSergey Zigachev 					dc,
5169b843c749SSergey Zigachev 					dm_new_crtc_state->stream,
5170b843c749SSergey Zigachev 					dc_new_plane_state,
5171b843c749SSergey Zigachev 					dm_state->context)) {
5172b843c749SSergey Zigachev 
5173b843c749SSergey Zigachev 				dc_plane_state_release(dc_new_plane_state);
5174b843c749SSergey Zigachev 				return -EINVAL;
5175b843c749SSergey Zigachev 			}
5176b843c749SSergey Zigachev 
5177b843c749SSergey Zigachev 			dm_new_plane_state->dc_state = dc_new_plane_state;
5178b843c749SSergey Zigachev 
5179b843c749SSergey Zigachev 			/* Tell DC to do a full surface update every time there
5180b843c749SSergey Zigachev 			 * is a plane change. Inefficient, but works for now.
5181b843c749SSergey Zigachev 			 */
5182b843c749SSergey Zigachev 			dm_new_plane_state->dc_state->update_flags.bits.full_update = 1;
5183b843c749SSergey Zigachev 
5184b843c749SSergey Zigachev 			*lock_and_validation_needed = true;
5185b843c749SSergey Zigachev 		}
5186b843c749SSergey Zigachev 	}
5187b843c749SSergey Zigachev 
5188b843c749SSergey Zigachev 
5189b843c749SSergey Zigachev 	return ret;
5190b843c749SSergey Zigachev }
5191b843c749SSergey Zigachev 
amdgpu_dm_atomic_check(struct drm_device * dev,struct drm_atomic_state * state)5192b843c749SSergey Zigachev static int amdgpu_dm_atomic_check(struct drm_device *dev,
5193b843c749SSergey Zigachev 				  struct drm_atomic_state *state)
5194b843c749SSergey Zigachev {
5195b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev->dev_private;
5196b843c749SSergey Zigachev 	struct dc *dc = adev->dm.dc;
5197b843c749SSergey Zigachev 	struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
5198b843c749SSergey Zigachev 	struct drm_connector *connector;
5199b843c749SSergey Zigachev 	struct drm_connector_state *old_con_state, *new_con_state;
5200b843c749SSergey Zigachev 	struct drm_crtc *crtc;
5201b843c749SSergey Zigachev 	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
5202b843c749SSergey Zigachev 	int ret, i;
5203b843c749SSergey Zigachev 
5204b843c749SSergey Zigachev 	/*
5205b843c749SSergey Zigachev 	 * This bool will be set for true for any modeset/reset
5206b843c749SSergey Zigachev 	 * or plane update which implies non fast surface update.
5207b843c749SSergey Zigachev 	 */
5208b843c749SSergey Zigachev 	bool lock_and_validation_needed = false;
5209b843c749SSergey Zigachev 
5210b843c749SSergey Zigachev 	ret = drm_atomic_helper_check_modeset(dev, state);
5211b843c749SSergey Zigachev 	if (ret)
5212b843c749SSergey Zigachev 		goto fail;
5213b843c749SSergey Zigachev 
5214b843c749SSergey Zigachev 	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
5215b843c749SSergey Zigachev 		if (!drm_atomic_crtc_needs_modeset(new_crtc_state) &&
5216b843c749SSergey Zigachev 		    !new_crtc_state->color_mgmt_changed)
5217b843c749SSergey Zigachev 			continue;
5218b843c749SSergey Zigachev 
5219b843c749SSergey Zigachev 		if (!new_crtc_state->enable)
5220b843c749SSergey Zigachev 			continue;
5221b843c749SSergey Zigachev 
5222b843c749SSergey Zigachev 		ret = drm_atomic_add_affected_connectors(state, crtc);
5223b843c749SSergey Zigachev 		if (ret)
5224b843c749SSergey Zigachev 			return ret;
5225b843c749SSergey Zigachev 
5226b843c749SSergey Zigachev 		ret = drm_atomic_add_affected_planes(state, crtc);
5227b843c749SSergey Zigachev 		if (ret)
5228b843c749SSergey Zigachev 			goto fail;
5229b843c749SSergey Zigachev 	}
5230b843c749SSergey Zigachev 
5231b843c749SSergey Zigachev 	dm_state->context = dc_create_state();
5232b843c749SSergey Zigachev 	ASSERT(dm_state->context);
5233b843c749SSergey Zigachev 	dc_resource_state_copy_construct_current(dc, dm_state->context);
5234b843c749SSergey Zigachev 
5235b843c749SSergey Zigachev 	/* Remove exiting planes if they are modified */
5236b843c749SSergey Zigachev 	ret = dm_update_planes_state(dc, state, false, &lock_and_validation_needed);
5237b843c749SSergey Zigachev 	if (ret) {
5238b843c749SSergey Zigachev 		goto fail;
5239b843c749SSergey Zigachev 	}
5240b843c749SSergey Zigachev 
5241b843c749SSergey Zigachev 	/* Disable all crtcs which require disable */
5242b843c749SSergey Zigachev 	ret = dm_update_crtcs_state(dc, state, false, &lock_and_validation_needed);
5243b843c749SSergey Zigachev 	if (ret) {
5244b843c749SSergey Zigachev 		goto fail;
5245b843c749SSergey Zigachev 	}
5246b843c749SSergey Zigachev 
5247b843c749SSergey Zigachev 	/* Enable all crtcs which require enable */
5248b843c749SSergey Zigachev 	ret = dm_update_crtcs_state(dc, state, true, &lock_and_validation_needed);
5249b843c749SSergey Zigachev 	if (ret) {
5250b843c749SSergey Zigachev 		goto fail;
5251b843c749SSergey Zigachev 	}
5252b843c749SSergey Zigachev 
5253b843c749SSergey Zigachev 	/* Add new/modified planes */
5254b843c749SSergey Zigachev 	ret = dm_update_planes_state(dc, state, true, &lock_and_validation_needed);
5255b843c749SSergey Zigachev 	if (ret) {
5256b843c749SSergey Zigachev 		goto fail;
5257b843c749SSergey Zigachev 	}
5258b843c749SSergey Zigachev 
5259b843c749SSergey Zigachev 	/* Run this here since we want to validate the streams we created */
5260b843c749SSergey Zigachev 	ret = drm_atomic_helper_check_planes(dev, state);
5261b843c749SSergey Zigachev 	if (ret)
5262b843c749SSergey Zigachev 		goto fail;
5263b843c749SSergey Zigachev 
5264b843c749SSergey Zigachev 	/* Check scaling and underscan changes*/
5265b843c749SSergey Zigachev 	/*TODO Removed scaling changes validation due to inability to commit
5266b843c749SSergey Zigachev 	 * new stream into context w\o causing full reset. Need to
5267b843c749SSergey Zigachev 	 * decide how to handle.
5268b843c749SSergey Zigachev 	 */
5269b843c749SSergey Zigachev 	for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
5270b843c749SSergey Zigachev 		struct dm_connector_state *dm_old_con_state = to_dm_connector_state(old_con_state);
5271b843c749SSergey Zigachev 		struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state);
5272b843c749SSergey Zigachev 		struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc);
5273b843c749SSergey Zigachev 
5274b843c749SSergey Zigachev 		/* Skip any modesets/resets */
5275b843c749SSergey Zigachev 		if (!acrtc || drm_atomic_crtc_needs_modeset(
5276b843c749SSergey Zigachev 				drm_atomic_get_new_crtc_state(state, &acrtc->base)))
5277b843c749SSergey Zigachev 			continue;
5278b843c749SSergey Zigachev 
5279b843c749SSergey Zigachev 		/* Skip any thing not scale or underscan changes */
5280b843c749SSergey Zigachev 		if (!is_scaling_state_different(dm_new_con_state, dm_old_con_state))
5281b843c749SSergey Zigachev 			continue;
5282b843c749SSergey Zigachev 
5283b843c749SSergey Zigachev 		lock_and_validation_needed = true;
5284b843c749SSergey Zigachev 	}
5285b843c749SSergey Zigachev 
5286b843c749SSergey Zigachev 	/*
5287b843c749SSergey Zigachev 	 * For full updates case when
5288b843c749SSergey Zigachev 	 * removing/adding/updating  streams on once CRTC while flipping
5289b843c749SSergey Zigachev 	 * on another CRTC,
5290b843c749SSergey Zigachev 	 * acquiring global lock  will guarantee that any such full
5291b843c749SSergey Zigachev 	 * update commit
5292b843c749SSergey Zigachev 	 * will wait for completion of any outstanding flip using DRMs
5293b843c749SSergey Zigachev 	 * synchronization events.
5294b843c749SSergey Zigachev 	 */
5295b843c749SSergey Zigachev 
5296b843c749SSergey Zigachev 	if (lock_and_validation_needed) {
5297b843c749SSergey Zigachev 
5298b843c749SSergey Zigachev 		ret = do_aquire_global_lock(dev, state);
5299b843c749SSergey Zigachev 		if (ret)
5300b843c749SSergey Zigachev 			goto fail;
5301b843c749SSergey Zigachev 
5302b843c749SSergey Zigachev 		if (dc_validate_global_state(dc, dm_state->context) != DC_OK) {
5303b843c749SSergey Zigachev 			ret = -EINVAL;
5304b843c749SSergey Zigachev 			goto fail;
5305b843c749SSergey Zigachev 		}
5306b843c749SSergey Zigachev 	}
5307b843c749SSergey Zigachev 
5308b843c749SSergey Zigachev 	/* Must be success */
5309b843c749SSergey Zigachev 	WARN_ON(ret);
5310b843c749SSergey Zigachev 	return ret;
5311b843c749SSergey Zigachev 
5312b843c749SSergey Zigachev fail:
5313b843c749SSergey Zigachev 	if (ret == -EDEADLK)
5314b843c749SSergey Zigachev 		DRM_DEBUG_DRIVER("Atomic check stopped to avoid deadlock.\n");
5315b843c749SSergey Zigachev 	else if (ret == -EINTR || ret == -EAGAIN || ret == -ERESTARTSYS)
5316b843c749SSergey Zigachev 		DRM_DEBUG_DRIVER("Atomic check stopped due to signal.\n");
5317b843c749SSergey Zigachev 	else
5318b843c749SSergey Zigachev 		DRM_DEBUG_DRIVER("Atomic check failed with err: %d \n", ret);
5319b843c749SSergey Zigachev 
5320b843c749SSergey Zigachev 	return ret;
5321b843c749SSergey Zigachev }
5322b843c749SSergey Zigachev 
is_dp_capable_without_timing_msa(struct dc * dc,struct amdgpu_dm_connector * amdgpu_dm_connector)5323b843c749SSergey Zigachev static bool is_dp_capable_without_timing_msa(struct dc *dc,
5324b843c749SSergey Zigachev 					     struct amdgpu_dm_connector *amdgpu_dm_connector)
5325b843c749SSergey Zigachev {
5326b843c749SSergey Zigachev 	uint8_t dpcd_data;
5327b843c749SSergey Zigachev 	bool capable = false;
5328b843c749SSergey Zigachev 
5329b843c749SSergey Zigachev 	if (amdgpu_dm_connector->dc_link &&
5330b843c749SSergey Zigachev 		dm_helpers_dp_read_dpcd(
5331b843c749SSergey Zigachev 				NULL,
5332b843c749SSergey Zigachev 				amdgpu_dm_connector->dc_link,
5333b843c749SSergey Zigachev 				DP_DOWN_STREAM_PORT_COUNT,
5334b843c749SSergey Zigachev 				&dpcd_data,
5335b843c749SSergey Zigachev 				sizeof(dpcd_data))) {
5336b843c749SSergey Zigachev 		capable = (dpcd_data & DP_MSA_TIMING_PAR_IGNORED) ? true:false;
5337b843c749SSergey Zigachev 	}
5338b843c749SSergey Zigachev 
5339b843c749SSergey Zigachev 	return capable;
5340b843c749SSergey Zigachev }
amdgpu_dm_add_sink_to_freesync_module(struct drm_connector * connector,struct edid * edid)5341b843c749SSergey Zigachev void amdgpu_dm_add_sink_to_freesync_module(struct drm_connector *connector,
5342b843c749SSergey Zigachev 					   struct edid *edid)
5343b843c749SSergey Zigachev {
5344b843c749SSergey Zigachev 	int i;
5345b843c749SSergey Zigachev 	bool edid_check_required;
5346b843c749SSergey Zigachev 	struct detailed_timing *timing;
5347b843c749SSergey Zigachev 	struct detailed_non_pixel *data;
5348b843c749SSergey Zigachev 	struct detailed_data_monitor_range *range;
5349b843c749SSergey Zigachev 	struct amdgpu_dm_connector *amdgpu_dm_connector =
5350b843c749SSergey Zigachev 			to_amdgpu_dm_connector(connector);
5351b843c749SSergey Zigachev 	struct dm_connector_state *dm_con_state;
5352b843c749SSergey Zigachev 
5353b843c749SSergey Zigachev 	struct drm_device *dev = connector->dev;
5354b843c749SSergey Zigachev 	struct amdgpu_device *adev = dev->dev_private;
5355b843c749SSergey Zigachev 
5356b843c749SSergey Zigachev 	if (!connector->state) {
5357b843c749SSergey Zigachev 		DRM_ERROR("%s - Connector has no state", __func__);
5358b843c749SSergey Zigachev 		return;
5359b843c749SSergey Zigachev 	}
5360b843c749SSergey Zigachev 
5361b843c749SSergey Zigachev 	dm_con_state = to_dm_connector_state(connector->state);
5362b843c749SSergey Zigachev 
5363b843c749SSergey Zigachev 	edid_check_required = false;
5364b843c749SSergey Zigachev 	if (!amdgpu_dm_connector->dc_sink) {
5365b843c749SSergey Zigachev 		DRM_ERROR("dc_sink NULL, could not add free_sync module.\n");
5366b843c749SSergey Zigachev 		return;
5367b843c749SSergey Zigachev 	}
5368b843c749SSergey Zigachev 	if (!adev->dm.freesync_module)
5369b843c749SSergey Zigachev 		return;
5370b843c749SSergey Zigachev 	/*
5371b843c749SSergey Zigachev 	 * if edid non zero restrict freesync only for dp and edp
5372b843c749SSergey Zigachev 	 */
5373b843c749SSergey Zigachev 	if (edid) {
5374b843c749SSergey Zigachev 		if (amdgpu_dm_connector->dc_sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT
5375b843c749SSergey Zigachev 			|| amdgpu_dm_connector->dc_sink->sink_signal == SIGNAL_TYPE_EDP) {
5376b843c749SSergey Zigachev 			edid_check_required = is_dp_capable_without_timing_msa(
5377b843c749SSergey Zigachev 						adev->dm.dc,
5378b843c749SSergey Zigachev 						amdgpu_dm_connector);
5379b843c749SSergey Zigachev 		}
5380b843c749SSergey Zigachev 	}
5381b843c749SSergey Zigachev 	dm_con_state->freesync_capable = false;
5382b843c749SSergey Zigachev 	if (edid_check_required == true && (edid->version > 1 ||
5383b843c749SSergey Zigachev 	   (edid->version == 1 && edid->revision > 1))) {
5384b843c749SSergey Zigachev 		for (i = 0; i < 4; i++) {
5385b843c749SSergey Zigachev 
5386b843c749SSergey Zigachev 			timing	= &edid->detailed_timings[i];
5387b843c749SSergey Zigachev 			data	= &timing->data.other_data;
5388b843c749SSergey Zigachev 			range	= &data->data.range;
5389b843c749SSergey Zigachev 			/*
5390b843c749SSergey Zigachev 			 * Check if monitor has continuous frequency mode
5391b843c749SSergey Zigachev 			 */
5392b843c749SSergey Zigachev 			if (data->type != EDID_DETAIL_MONITOR_RANGE)
5393b843c749SSergey Zigachev 				continue;
5394b843c749SSergey Zigachev 			/*
5395b843c749SSergey Zigachev 			 * Check for flag range limits only. If flag == 1 then
5396b843c749SSergey Zigachev 			 * no additional timing information provided.
5397b843c749SSergey Zigachev 			 * Default GTF, GTF Secondary curve and CVT are not
5398b843c749SSergey Zigachev 			 * supported
5399b843c749SSergey Zigachev 			 */
5400b843c749SSergey Zigachev 			if (range->flags != 1)
5401b843c749SSergey Zigachev 				continue;
5402b843c749SSergey Zigachev 
5403b843c749SSergey Zigachev 			amdgpu_dm_connector->min_vfreq = range->min_vfreq;
5404b843c749SSergey Zigachev 			amdgpu_dm_connector->max_vfreq = range->max_vfreq;
5405b843c749SSergey Zigachev 			amdgpu_dm_connector->pixel_clock_mhz =
5406b843c749SSergey Zigachev 				range->pixel_clock_mhz * 10;
5407b843c749SSergey Zigachev 			break;
5408b843c749SSergey Zigachev 		}
5409b843c749SSergey Zigachev 
5410b843c749SSergey Zigachev 		if (amdgpu_dm_connector->max_vfreq -
5411b843c749SSergey Zigachev 				amdgpu_dm_connector->min_vfreq > 10) {
5412b843c749SSergey Zigachev 			amdgpu_dm_connector->caps.supported = true;
5413b843c749SSergey Zigachev 			amdgpu_dm_connector->caps.min_refresh_in_micro_hz =
5414b843c749SSergey Zigachev 					amdgpu_dm_connector->min_vfreq * 1000000;
5415b843c749SSergey Zigachev 			amdgpu_dm_connector->caps.max_refresh_in_micro_hz =
5416b843c749SSergey Zigachev 					amdgpu_dm_connector->max_vfreq * 1000000;
5417b843c749SSergey Zigachev 			dm_con_state->freesync_capable = true;
5418b843c749SSergey Zigachev 		}
5419b843c749SSergey Zigachev 	}
5420b843c749SSergey Zigachev 
5421b843c749SSergey Zigachev 	/*
5422b843c749SSergey Zigachev 	 * TODO figure out how to notify user-mode or DRM of freesync caps
5423b843c749SSergey Zigachev 	 * once we figure out how to deal with freesync in an upstreamable
5424b843c749SSergey Zigachev 	 * fashion
5425b843c749SSergey Zigachev 	 */
5426b843c749SSergey Zigachev 
5427b843c749SSergey Zigachev }
5428b843c749SSergey Zigachev 
amdgpu_dm_remove_sink_from_freesync_module(struct drm_connector * connector)5429b843c749SSergey Zigachev void amdgpu_dm_remove_sink_from_freesync_module(struct drm_connector *connector)
5430b843c749SSergey Zigachev {
5431b843c749SSergey Zigachev 	/*
5432b843c749SSergey Zigachev 	 * TODO fill in once we figure out how to deal with freesync in
5433b843c749SSergey Zigachev 	 * an upstreamable fashion
5434b843c749SSergey Zigachev 	 */
5435b843c749SSergey Zigachev }
5436