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 	if (!aconnector->vsdb_info.replay_mode)
50 		return false;
51 
52 	// Check the eDP version
53 	if (dpcd_caps->edp_rev < EDP_REVISION_13)
54 		return false;
55 
56 	if (!dpcd_caps->alpm_caps.bits.AUX_WAKE_ALPM_CAP)
57 		return false;
58 
59 	// Check adaptive sync support cap
60 	if (!as_caps->dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT)
61 		return false;
62 
63 	return true;
64 }
65 
66 /*
67  * amdgpu_dm_setup_replay() - setup replay configuration
68  * @link: link
69  * @aconnector: aconnector
70  *
71  */
72 bool amdgpu_dm_setup_replay(struct dc_link *link, struct amdgpu_dm_connector *aconnector)
73 {
74 	struct replay_config pr_config;
75 	union replay_debug_flags *debug_flags = NULL;
76 
77 	// For eDP, if Replay is supported, return true to skip checks
78 	if (link->replay_settings.config.replay_supported)
79 		return true;
80 
81 	if (!dc_is_embedded_signal(link->connector_signal))
82 		return false;
83 
84 	if (link->panel_config.psr.disallow_replay)
85 		return false;
86 
87 	if (!link_supports_replay(link, aconnector))
88 		return false;
89 
90 	// Mark Replay is supported in link and update related attributes
91 	pr_config.replay_supported = true;
92 	pr_config.replay_power_opt_supported = 0;
93 	pr_config.replay_enable_option |= pr_enable_option_static_screen;
94 	pr_config.replay_timing_sync_supported = aconnector->max_vfreq >= 2 * aconnector->min_vfreq ? true : false;
95 
96 	if (!pr_config.replay_timing_sync_supported)
97 		pr_config.replay_enable_option &= ~pr_enable_option_general_ui;
98 
99 	debug_flags = (union replay_debug_flags *)&pr_config.debug_flags;
100 	debug_flags->u32All = 0;
101 	debug_flags->bitfields.visual_confirm =
102 		link->ctx->dc->debug.visual_confirm == VISUAL_CONFIRM_REPLAY ? true : false;
103 
104 	link->replay_settings.replay_feature_enabled = true;
105 
106 	init_replay_config(link, &pr_config);
107 
108 	return true;
109 }
110 
111 
112 /*
113  * amdgpu_dm_replay_enable() - enable replay f/w
114  * @stream: stream state
115  *
116  * Return: true if success
117  */
118 bool amdgpu_dm_replay_enable(struct dc_stream_state *stream, bool wait)
119 {
120 	uint64_t state;
121 	unsigned int retry_count;
122 	bool replay_active = true;
123 	const unsigned int max_retry = 1000;
124 	bool force_static = true;
125 	struct dc_link *link = NULL;
126 
127 
128 	if (stream == NULL)
129 		return false;
130 
131 	link = stream->link;
132 
133 	if (link == NULL)
134 		return false;
135 
136 	link->dc->link_srv->edp_setup_replay(link, stream);
137 
138 	link->dc->link_srv->edp_set_replay_allow_active(link, NULL, false, false, NULL);
139 
140 	link->dc->link_srv->edp_set_replay_allow_active(link, &replay_active, false, true, NULL);
141 
142 	if (wait == true) {
143 
144 		for (retry_count = 0; retry_count <= max_retry; retry_count++) {
145 			dc_link_get_replay_state(link, &state);
146 			if (replay_active) {
147 				if (state != REPLAY_STATE_0 &&
148 					(!force_static || state == REPLAY_STATE_3))
149 					break;
150 			} else {
151 				if (state == REPLAY_STATE_0)
152 					break;
153 			}
154 			udelay(500);
155 		}
156 
157 		/* assert if max retry hit */
158 		if (retry_count >= max_retry)
159 			ASSERT(0);
160 	} else {
161 		/* To-do: Add trace log */
162 	}
163 
164 	return true;
165 }
166 
167 /*
168  * amdgpu_dm_replay_disable() - disable replay f/w
169  * @stream:  stream state
170  *
171  * Return: true if success
172  */
173 bool amdgpu_dm_replay_disable(struct dc_stream_state *stream)
174 {
175 
176 	if (stream->link) {
177 		DRM_DEBUG_DRIVER("Disabling replay...\n");
178 		stream->link->dc->link_srv->edp_set_replay_allow_active(stream->link, NULL, false, false, NULL);
179 		return true;
180 	}
181 
182 	return false;
183 }
184