forked from ~ljy/RK356X_SDK_RELEASE

hc
2023-12-08 01573e231f18eb2d99162747186f59511f56b64d
kernel/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
....@@ -24,34 +24,67 @@
2424 */
2525
2626 #include <drm/drm_crtc.h>
27
+#include <drm/drm_vblank.h>
2728
2829 #include "amdgpu.h"
2930 #include "amdgpu_dm.h"
3031 #include "dc.h"
3132
32
-enum amdgpu_dm_pipe_crc_source {
33
- AMDGPU_DM_PIPE_CRC_SOURCE_NONE = 0,
34
- AMDGPU_DM_PIPE_CRC_SOURCE_AUTO,
35
- AMDGPU_DM_PIPE_CRC_SOURCE_MAX,
36
- AMDGPU_DM_PIPE_CRC_SOURCE_INVALID = -1,
33
+static const char *const pipe_crc_sources[] = {
34
+ "none",
35
+ "crtc",
36
+ "crtc dither",
37
+ "dprx",
38
+ "dprx dither",
39
+ "auto",
3740 };
3841
3942 static enum amdgpu_dm_pipe_crc_source dm_parse_crc_source(const char *source)
4043 {
4144 if (!source || !strcmp(source, "none"))
4245 return AMDGPU_DM_PIPE_CRC_SOURCE_NONE;
43
- if (!strcmp(source, "auto"))
44
- return AMDGPU_DM_PIPE_CRC_SOURCE_AUTO;
46
+ if (!strcmp(source, "auto") || !strcmp(source, "crtc"))
47
+ return AMDGPU_DM_PIPE_CRC_SOURCE_CRTC;
48
+ if (!strcmp(source, "dprx"))
49
+ return AMDGPU_DM_PIPE_CRC_SOURCE_DPRX;
50
+ if (!strcmp(source, "crtc dither"))
51
+ return AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER;
52
+ if (!strcmp(source, "dprx dither"))
53
+ return AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER;
4554
4655 return AMDGPU_DM_PIPE_CRC_SOURCE_INVALID;
4756 }
4857
49
-int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
58
+static bool dm_is_crc_source_crtc(enum amdgpu_dm_pipe_crc_source src)
5059 {
51
- struct dm_crtc_state *crtc_state = to_dm_crtc_state(crtc->state);
52
- struct dc_stream_state *stream_state = crtc_state->stream;
53
- bool enable;
60
+ return (src == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC) ||
61
+ (src == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER);
62
+}
5463
64
+static bool dm_is_crc_source_dprx(enum amdgpu_dm_pipe_crc_source src)
65
+{
66
+ return (src == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX) ||
67
+ (src == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER);
68
+}
69
+
70
+static bool dm_need_crc_dither(enum amdgpu_dm_pipe_crc_source src)
71
+{
72
+ return (src == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER) ||
73
+ (src == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER) ||
74
+ (src == AMDGPU_DM_PIPE_CRC_SOURCE_NONE);
75
+}
76
+
77
+const char *const *amdgpu_dm_crtc_get_crc_sources(struct drm_crtc *crtc,
78
+ size_t *count)
79
+{
80
+ *count = ARRAY_SIZE(pipe_crc_sources);
81
+ return pipe_crc_sources;
82
+}
83
+
84
+int
85
+amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc, const char *src_name,
86
+ size_t *values_cnt)
87
+{
5588 enum amdgpu_dm_pipe_crc_source source = dm_parse_crc_source(src_name);
5689
5790 if (source < 0) {
....@@ -60,36 +93,194 @@
6093 return -EINVAL;
6194 }
6295
63
- if (!stream_state) {
64
- DRM_ERROR("No stream state for CRTC%d\n", crtc->index);
96
+ *values_cnt = 3;
97
+ return 0;
98
+}
99
+
100
+int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
101
+ struct dm_crtc_state *dm_crtc_state,
102
+ enum amdgpu_dm_pipe_crc_source source)
103
+{
104
+ struct amdgpu_device *adev = drm_to_adev(crtc->dev);
105
+ struct dc_stream_state *stream_state = dm_crtc_state->stream;
106
+ bool enable = amdgpu_dm_is_valid_crc_source(source);
107
+ int ret = 0;
108
+
109
+ /* Configuration will be deferred to stream enable. */
110
+ if (!stream_state)
111
+ return 0;
112
+
113
+ mutex_lock(&adev->dm.dc_lock);
114
+
115
+ /* Enable CRTC CRC generation if necessary. */
116
+ if (dm_is_crc_source_crtc(source) || source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE) {
117
+ if (!dc_stream_configure_crc(stream_state->ctx->dc,
118
+ stream_state, enable, enable)) {
119
+ ret = -EINVAL;
120
+ goto unlock;
121
+ }
122
+ }
123
+
124
+ /* Configure dithering */
125
+ if (!dm_need_crc_dither(source)) {
126
+ dc_stream_set_dither_option(stream_state, DITHER_OPTION_TRUN8);
127
+ dc_stream_set_dyn_expansion(stream_state->ctx->dc, stream_state,
128
+ DYN_EXPANSION_DISABLE);
129
+ } else {
130
+ dc_stream_set_dither_option(stream_state,
131
+ DITHER_OPTION_DEFAULT);
132
+ dc_stream_set_dyn_expansion(stream_state->ctx->dc, stream_state,
133
+ DYN_EXPANSION_AUTO);
134
+ }
135
+
136
+unlock:
137
+ mutex_unlock(&adev->dm.dc_lock);
138
+
139
+ return ret;
140
+}
141
+
142
+int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
143
+{
144
+ enum amdgpu_dm_pipe_crc_source source = dm_parse_crc_source(src_name);
145
+ struct drm_crtc_commit *commit;
146
+ struct dm_crtc_state *crtc_state;
147
+ struct drm_dp_aux *aux = NULL;
148
+ bool enable = false;
149
+ bool enabled = false;
150
+ int ret = 0;
151
+
152
+ if (source < 0) {
153
+ DRM_DEBUG_DRIVER("Unknown CRC source %s for CRTC%d\n",
154
+ src_name, crtc->index);
65155 return -EINVAL;
66156 }
67157
68
- enable = (source == AMDGPU_DM_PIPE_CRC_SOURCE_AUTO);
158
+ ret = drm_modeset_lock(&crtc->mutex, NULL);
159
+ if (ret)
160
+ return ret;
69161
70
- if (!dc_stream_configure_crc(stream_state->ctx->dc, stream_state,
71
- enable, enable))
72
- return -EINVAL;
162
+ spin_lock(&crtc->commit_lock);
163
+ commit = list_first_entry_or_null(&crtc->commit_list,
164
+ struct drm_crtc_commit, commit_entry);
165
+ if (commit)
166
+ drm_crtc_commit_get(commit);
167
+ spin_unlock(&crtc->commit_lock);
73168
74
- /* When enabling CRC, we should also disable dithering. */
75
- dc_stream_set_dither_option(stream_state,
76
- enable ? DITHER_OPTION_TRUN8
77
- : DITHER_OPTION_DEFAULT);
169
+ if (commit) {
170
+ /*
171
+ * Need to wait for all outstanding programming to complete
172
+ * in commit tail since it can modify CRC related fields and
173
+ * hardware state. Since we're holding the CRTC lock we're
174
+ * guaranteed that no other commit work can be queued off
175
+ * before we modify the state below.
176
+ */
177
+ ret = wait_for_completion_interruptible_timeout(
178
+ &commit->hw_done, 10 * HZ);
179
+ if (ret)
180
+ goto cleanup;
181
+ }
182
+
183
+ enable = amdgpu_dm_is_valid_crc_source(source);
184
+ crtc_state = to_dm_crtc_state(crtc->state);
185
+
186
+ /*
187
+ * USER REQ SRC | CURRENT SRC | BEHAVIOR
188
+ * -----------------------------
189
+ * None | None | Do nothing
190
+ * None | CRTC | Disable CRTC CRC, set default to dither
191
+ * None | DPRX | Disable DPRX CRC, need 'aux', set default to dither
192
+ * None | CRTC DITHER | Disable CRTC CRC
193
+ * None | DPRX DITHER | Disable DPRX CRC, need 'aux'
194
+ * CRTC | XXXX | Enable CRTC CRC, no dither
195
+ * DPRX | XXXX | Enable DPRX CRC, need 'aux', no dither
196
+ * CRTC DITHER | XXXX | Enable CRTC CRC, set dither
197
+ * DPRX DITHER | XXXX | Enable DPRX CRC, need 'aux', set dither
198
+ */
199
+ if (dm_is_crc_source_dprx(source) ||
200
+ (source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE &&
201
+ dm_is_crc_source_dprx(crtc_state->crc_src))) {
202
+ struct amdgpu_dm_connector *aconn = NULL;
203
+ struct drm_connector *connector;
204
+ struct drm_connector_list_iter conn_iter;
205
+
206
+ drm_connector_list_iter_begin(crtc->dev, &conn_iter);
207
+ drm_for_each_connector_iter(connector, &conn_iter) {
208
+ if (!connector->state || connector->state->crtc != crtc)
209
+ continue;
210
+
211
+ aconn = to_amdgpu_dm_connector(connector);
212
+ break;
213
+ }
214
+ drm_connector_list_iter_end(&conn_iter);
215
+
216
+ if (!aconn) {
217
+ DRM_DEBUG_DRIVER("No amd connector matching CRTC-%d\n", crtc->index);
218
+ ret = -EINVAL;
219
+ goto cleanup;
220
+ }
221
+
222
+ aux = &aconn->dm_dp_aux.aux;
223
+
224
+ if (!aux) {
225
+ DRM_DEBUG_DRIVER("No dp aux for amd connector\n");
226
+ ret = -EINVAL;
227
+ goto cleanup;
228
+ }
229
+
230
+ if ((aconn->base.connector_type != DRM_MODE_CONNECTOR_DisplayPort) &&
231
+ (aconn->base.connector_type != DRM_MODE_CONNECTOR_eDP)) {
232
+ DRM_DEBUG_DRIVER("No DP connector available for CRC source\n");
233
+ ret = -EINVAL;
234
+ goto cleanup;
235
+ }
236
+
237
+ }
238
+
239
+ if (amdgpu_dm_crtc_configure_crc_source(crtc, crtc_state, source)) {
240
+ ret = -EINVAL;
241
+ goto cleanup;
242
+ }
78243
79244 /*
80245 * Reading the CRC requires the vblank interrupt handler to be
81246 * enabled. Keep a reference until CRC capture stops.
82247 */
83
- if (!crtc_state->crc_enabled && enable)
84
- drm_crtc_vblank_get(crtc);
85
- else if (crtc_state->crc_enabled && !enable)
86
- drm_crtc_vblank_put(crtc);
248
+ enabled = amdgpu_dm_is_valid_crc_source(crtc_state->crc_src);
249
+ if (!enabled && enable) {
250
+ ret = drm_crtc_vblank_get(crtc);
251
+ if (ret)
252
+ goto cleanup;
87253
88
- crtc_state->crc_enabled = enable;
254
+ if (dm_is_crc_source_dprx(source)) {
255
+ if (drm_dp_start_crc(aux, crtc)) {
256
+ DRM_DEBUG_DRIVER("dp start crc failed\n");
257
+ ret = -EINVAL;
258
+ goto cleanup;
259
+ }
260
+ }
261
+ } else if (enabled && !enable) {
262
+ drm_crtc_vblank_put(crtc);
263
+ if (dm_is_crc_source_dprx(source)) {
264
+ if (drm_dp_stop_crc(aux)) {
265
+ DRM_DEBUG_DRIVER("dp stop crc failed\n");
266
+ ret = -EINVAL;
267
+ goto cleanup;
268
+ }
269
+ }
270
+ }
271
+
272
+ crtc_state->crc_src = source;
89273
90274 /* Reset crc_skipped on dm state */
91275 crtc_state->crc_skip_count = 0;
92
- return 0;
276
+
277
+cleanup:
278
+ if (commit)
279
+ drm_crtc_commit_put(commit);
280
+
281
+ drm_modeset_unlock(&crtc->mutex);
282
+
283
+ return ret;
93284 }
94285
95286 /**
....@@ -112,7 +303,7 @@
112303 stream_state = crtc_state->stream;
113304
114305 /* Early return if CRC capture is not enabled. */
115
- if (!crtc_state->crc_enabled)
306
+ if (!amdgpu_dm_is_valid_crc_source(crtc_state->crc_src))
116307 return;
117308
118309 /*
....@@ -126,10 +317,12 @@
126317 return;
127318 }
128319
129
- if (!dc_stream_get_crc(stream_state->ctx->dc, stream_state,
130
- &crcs[0], &crcs[1], &crcs[2]))
131
- return;
320
+ if (dm_is_crc_source_crtc(crtc_state->crc_src)) {
321
+ if (!dc_stream_get_crc(stream_state->ctx->dc, stream_state,
322
+ &crcs[0], &crcs[1], &crcs[2]))
323
+ return;
132324
133
- drm_crtc_add_crc_entry(crtc, true,
134
- drm_crtc_accurate_vblank_count(crtc), crcs);
325
+ drm_crtc_add_crc_entry(crtc, true,
326
+ drm_crtc_accurate_vblank_count(crtc), crcs);
327
+ }
135328 }