1 /*
2  * Copyright 2023 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: AMD
23  *
24  */
25 
26 #include "amdgpu_dm_replay.h"
27 #include "dc.h"
28 #include "dm_helpers.h"
29 #include "amdgpu_dm.h"
30 #include "modules/power/power_helpers.h"
31 #include "dmub/inc/dmub_cmd.h"
32 #include "dc/inc/link.h"
33 
34 /*
35  * link_supports_replay() - check if the link supports replay
36  * @link: link
37  * @aconnector: aconnector
38  *
39  */
40 static bool link_supports_replay(struct dc_link *link, struct amdgpu_dm_connector *aconnector)
41 {
42 	struct dm_connector_state *state = to_dm_connector_state(aconnector->base.state);
43 	struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
44 	struct adaptive_sync_caps *as_caps = &link->dpcd_caps.adaptive_sync_caps;
45 
46 	if (!state->freesync_capable)
47 		return false;
48 
49 	// Check the eDP version
50 	if (dpcd_caps->edp_rev < EDP_REVISION_13)
51 		return false;
52 
53 	if (!dpcd_caps->alpm_caps.bits.AUX_WAKE_ALPM_CAP)
54 		return false;
55 
56 	// Check adaptive sync support cap
57 	if (!as_caps->dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT)
58 		return false;
59 
60 	return true;
61 }
62 
63 /*
64  * amdgpu_dm_setup_replay() - setup replay configuration
65  * @link: link
66  * @aconnector: aconnector
67  *
68  */
69 bool amdgpu_dm_setup_replay(struct dc_link *link, struct amdgpu_dm_connector *aconnector)
70 {
71 	struct replay_config pr_config;
72 	union replay_debug_flags *debug_flags = NULL;
73 
74 	if (!dc_is_embedded_signal(link->connector_signal))
75 		return false;
76 
77 	if (link->panel_config.psr.disallow_replay)
78 		return false;
79 
80 	if (!link_supports_replay(link, aconnector))
81 		return false;
82 
83 	// Mark Replay is supported in link and update related attributes
84 	pr_config.replay_supported = true;
85 	pr_config.replay_power_opt_supported = 0;
86 	pr_config.replay_enable_option |= pr_enable_option_static_screen;
87 	pr_config.replay_timing_sync_supported = aconnector->max_vfreq >= 2 * aconnector->min_vfreq ? true : false;
88 
89 	if (!pr_config.replay_timing_sync_supported)
90 		pr_config.replay_enable_option &= ~pr_enable_option_general_ui;
91 
92 	debug_flags = (union replay_debug_flags *)&pr_config.debug_flags;
93 	debug_flags->u32All = 0;
94 	debug_flags->bitfields.visual_confirm =
95 		link->ctx->dc->debug.visual_confirm == VISUAL_CONFIRM_REPLAY ? true : false;
96 
97 	link->replay_settings.replay_feature_enabled = true;
98 
99 	init_replay_config(link, &pr_config);
100 
101 	return true;
102 }
103 
104 
105 /*
106  * amdgpu_dm_replay_enable() - enable replay f/w
107  * @stream: stream state
108  *
109  * Return: true if success
110  */
111 bool amdgpu_dm_replay_enable(struct dc_stream_state *stream, bool wait)
112 {
113 	uint64_t state;
114 	unsigned int retry_count;
115 	bool replay_active = true;
116 	const unsigned int max_retry = 1000;
117 	bool force_static = true;
118 	struct dc_link *link = NULL;
119 
120 
121 	if (stream == NULL)
122 		return false;
123 
124 	link = stream->link;
125 
126 	if (link == NULL)
127 		return false;
128 
129 	link->dc->link_srv->edp_setup_replay(link, stream);
130 
131 	link->dc->link_srv->edp_set_replay_allow_active(link, NULL, false, false, NULL);
132 
133 	link->dc->link_srv->edp_set_replay_allow_active(link, &replay_active, false, true, NULL);
134 
135 	if (wait == true) {
136 
137 		for (retry_count = 0; retry_count <= max_retry; retry_count++) {
138 			dc_link_get_replay_state(link, &state);
139 			if (replay_active) {
140 				if (state != REPLAY_STATE_0 &&
141 					(!force_static || state == REPLAY_STATE_3))
142 					break;
143 			} else {
144 				if (state == REPLAY_STATE_0)
145 					break;
146 			}
147 			udelay(500);
148 		}
149 
150 		/* assert if max retry hit */
151 		if (retry_count >= max_retry)
152 			ASSERT(0);
153 	} else {
154 		/* To-do: Add trace log */
155 	}
156 
157 	return true;
158 }
159 
160 /*
161  * amdgpu_dm_replay_disable() - disable replay f/w
162  * @stream:  stream state
163  *
164  * Return: true if success
165  */
166 bool amdgpu_dm_replay_disable(struct dc_stream_state *stream)
167 {
168 
169 	if (stream->link) {
170 		DRM_DEBUG_DRIVER("Disabling replay...\n");
171 		stream->link->dc->link_srv->edp_set_replay_allow_active(stream->link, NULL, false, false, NULL);
172 		return true;
173 	}
174 
175 	return false;
176 }
177