xref: /linux/drivers/gpu/drm/display/drm_hdmi_state_helper.c (revision 2c1ed907520c50326b8f604907a8478b27881a2e)
1 // SPDX-License-Identifier: MIT
2 
3 #include <drm/drm_atomic.h>
4 #include <drm/drm_connector.h>
5 #include <drm/drm_edid.h>
6 #include <drm/drm_print.h>
7 
8 #include <drm/display/drm_hdmi_audio_helper.h>
9 #include <drm/display/drm_hdmi_helper.h>
10 #include <drm/display/drm_hdmi_state_helper.h>
11 
12 /**
13  * __drm_atomic_helper_connector_hdmi_reset() - Initializes all HDMI @drm_connector_state resources
14  * @connector: DRM connector
15  * @new_conn_state: connector state to reset
16  *
17  * Initializes all HDMI resources from a @drm_connector_state without
18  * actually allocating it. This is useful for HDMI drivers, in
19  * combination with __drm_atomic_helper_connector_reset() or
20  * drm_atomic_helper_connector_reset().
21  */
__drm_atomic_helper_connector_hdmi_reset(struct drm_connector * connector,struct drm_connector_state * new_conn_state)22 void __drm_atomic_helper_connector_hdmi_reset(struct drm_connector *connector,
23 					      struct drm_connector_state *new_conn_state)
24 {
25 	unsigned int max_bpc = connector->max_bpc;
26 
27 	new_conn_state->max_bpc = max_bpc;
28 	new_conn_state->max_requested_bpc = max_bpc;
29 	new_conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_AUTO;
30 }
31 EXPORT_SYMBOL(__drm_atomic_helper_connector_hdmi_reset);
32 
33 static const struct drm_display_mode *
connector_state_get_mode(const struct drm_connector_state * conn_state)34 connector_state_get_mode(const struct drm_connector_state *conn_state)
35 {
36 	struct drm_atomic_state *state;
37 	struct drm_crtc_state *crtc_state;
38 	struct drm_crtc *crtc;
39 
40 	state = conn_state->state;
41 	if (!state)
42 		return NULL;
43 
44 	crtc = conn_state->crtc;
45 	if (!crtc)
46 		return NULL;
47 
48 	crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
49 	if (!crtc_state)
50 		return NULL;
51 
52 	return &crtc_state->mode;
53 }
54 
hdmi_is_limited_range(const struct drm_connector * connector,const struct drm_connector_state * conn_state)55 static bool hdmi_is_limited_range(const struct drm_connector *connector,
56 				  const struct drm_connector_state *conn_state)
57 {
58 	const struct drm_display_info *info = &connector->display_info;
59 	const struct drm_display_mode *mode =
60 		connector_state_get_mode(conn_state);
61 
62 	/*
63 	 * The Broadcast RGB property only applies to RGB format, and
64 	 * i915 just assumes limited range for YCbCr output, so let's
65 	 * just do the same.
66 	 */
67 	if (conn_state->hdmi.output_format != HDMI_COLORSPACE_RGB)
68 		return true;
69 
70 	if (conn_state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_FULL)
71 		return false;
72 
73 	if (conn_state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_LIMITED)
74 		return true;
75 
76 	if (!info->is_hdmi)
77 		return false;
78 
79 	return drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED;
80 }
81 
82 static bool
sink_supports_format_bpc(const struct drm_connector * connector,const struct drm_display_info * info,const struct drm_display_mode * mode,unsigned int format,unsigned int bpc)83 sink_supports_format_bpc(const struct drm_connector *connector,
84 			 const struct drm_display_info *info,
85 			 const struct drm_display_mode *mode,
86 			 unsigned int format, unsigned int bpc)
87 {
88 	struct drm_device *dev = connector->dev;
89 	u8 vic = drm_match_cea_mode(mode);
90 
91 	/*
92 	 * CTA-861-F, section 5.4 - Color Coding & Quantization states
93 	 * that the bpc must be 8, 10, 12 or 16 except for the default
94 	 * 640x480 VIC1 where the value must be 8.
95 	 *
96 	 * The definition of default here is ambiguous but the spec
97 	 * refers to VIC1 being the default timing in several occasions
98 	 * so our understanding is that for the default timing (ie,
99 	 * VIC1), the bpc must be 8.
100 	 */
101 	if (vic == 1 && bpc != 8) {
102 		drm_dbg_kms(dev, "VIC1 requires a bpc of 8, got %u\n", bpc);
103 		return false;
104 	}
105 
106 	if (!info->is_hdmi &&
107 	    (format != HDMI_COLORSPACE_RGB || bpc != 8)) {
108 		drm_dbg_kms(dev, "DVI Monitors require an RGB output at 8 bpc\n");
109 		return false;
110 	}
111 
112 	if (!(connector->hdmi.supported_formats & BIT(format))) {
113 		drm_dbg_kms(dev, "%s format unsupported by the connector.\n",
114 			    drm_hdmi_connector_get_output_format_name(format));
115 		return false;
116 	}
117 
118 	switch (format) {
119 	case HDMI_COLORSPACE_RGB:
120 		drm_dbg_kms(dev, "RGB Format, checking the constraints.\n");
121 
122 		/*
123 		 * In some cases, like when the EDID readout fails, or
124 		 * is not an HDMI compliant EDID for some reason, the
125 		 * color_formats field will be blank and not report any
126 		 * format supported. In such a case, assume that RGB is
127 		 * supported so we can keep things going and light up
128 		 * the display.
129 		 */
130 		if (!(info->color_formats & DRM_COLOR_FORMAT_RGB444))
131 			drm_warn(dev, "HDMI Sink doesn't support RGB, something's wrong.\n");
132 
133 		if (bpc == 10 && !(info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30)) {
134 			drm_dbg_kms(dev, "10 BPC but sink doesn't support Deep Color 30.\n");
135 			return false;
136 		}
137 
138 		if (bpc == 12 && !(info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36)) {
139 			drm_dbg_kms(dev, "12 BPC but sink doesn't support Deep Color 36.\n");
140 			return false;
141 		}
142 
143 		drm_dbg_kms(dev, "RGB format supported in that configuration.\n");
144 
145 		return true;
146 
147 	case HDMI_COLORSPACE_YUV420:
148 		/* TODO: YUV420 is unsupported at the moment. */
149 		drm_dbg_kms(dev, "YUV420 format isn't supported yet.\n");
150 		return false;
151 
152 	case HDMI_COLORSPACE_YUV422:
153 		drm_dbg_kms(dev, "YUV422 format, checking the constraints.\n");
154 
155 		if (!(info->color_formats & DRM_COLOR_FORMAT_YCBCR422)) {
156 			drm_dbg_kms(dev, "Sink doesn't support YUV422.\n");
157 			return false;
158 		}
159 
160 		if (bpc > 12) {
161 			drm_dbg_kms(dev, "YUV422 only supports 12 bpc or lower.\n");
162 			return false;
163 		}
164 
165 		/*
166 		 * HDMI Spec 1.3 - Section 6.5 Pixel Encodings and Color Depth
167 		 * states that Deep Color is not relevant for YUV422 so we
168 		 * don't need to check the Deep Color bits in the EDIDs here.
169 		 */
170 
171 		drm_dbg_kms(dev, "YUV422 format supported in that configuration.\n");
172 
173 		return true;
174 
175 	case HDMI_COLORSPACE_YUV444:
176 		drm_dbg_kms(dev, "YUV444 format, checking the constraints.\n");
177 
178 		if (!(info->color_formats & DRM_COLOR_FORMAT_YCBCR444)) {
179 			drm_dbg_kms(dev, "Sink doesn't support YUV444.\n");
180 			return false;
181 		}
182 
183 		if (bpc == 10 && !(info->edid_hdmi_ycbcr444_dc_modes & DRM_EDID_HDMI_DC_30)) {
184 			drm_dbg_kms(dev, "10 BPC but sink doesn't support Deep Color 30.\n");
185 			return false;
186 		}
187 
188 		if (bpc == 12 && !(info->edid_hdmi_ycbcr444_dc_modes & DRM_EDID_HDMI_DC_36)) {
189 			drm_dbg_kms(dev, "12 BPC but sink doesn't support Deep Color 36.\n");
190 			return false;
191 		}
192 
193 		drm_dbg_kms(dev, "YUV444 format supported in that configuration.\n");
194 
195 		return true;
196 	}
197 
198 	drm_dbg_kms(dev, "Unsupported pixel format.\n");
199 	return false;
200 }
201 
202 static enum drm_mode_status
hdmi_clock_valid(const struct drm_connector * connector,const struct drm_display_mode * mode,unsigned long long clock)203 hdmi_clock_valid(const struct drm_connector *connector,
204 		 const struct drm_display_mode *mode,
205 		 unsigned long long clock)
206 {
207 	const struct drm_connector_hdmi_funcs *funcs = connector->hdmi.funcs;
208 	const struct drm_display_info *info = &connector->display_info;
209 
210 	if (info->max_tmds_clock && clock > info->max_tmds_clock * 1000)
211 		return MODE_CLOCK_HIGH;
212 
213 	if (funcs && funcs->tmds_char_rate_valid) {
214 		enum drm_mode_status status;
215 
216 		status = funcs->tmds_char_rate_valid(connector, mode, clock);
217 		if (status != MODE_OK)
218 			return status;
219 	}
220 
221 	return MODE_OK;
222 }
223 
224 static int
hdmi_compute_clock(const struct drm_connector * connector,struct drm_connector_state * conn_state,const struct drm_display_mode * mode,unsigned int bpc,enum hdmi_colorspace fmt)225 hdmi_compute_clock(const struct drm_connector *connector,
226 		   struct drm_connector_state *conn_state,
227 		   const struct drm_display_mode *mode,
228 		   unsigned int bpc, enum hdmi_colorspace fmt)
229 {
230 	enum drm_mode_status status;
231 	unsigned long long clock;
232 
233 	clock = drm_hdmi_compute_mode_clock(mode, bpc, fmt);
234 	if (!clock)
235 		return -EINVAL;
236 
237 	status = hdmi_clock_valid(connector, mode, clock);
238 	if (status != MODE_OK)
239 		return -EINVAL;
240 
241 	conn_state->hdmi.tmds_char_rate = clock;
242 
243 	return 0;
244 }
245 
246 static bool
hdmi_try_format_bpc(const struct drm_connector * connector,struct drm_connector_state * conn_state,const struct drm_display_mode * mode,unsigned int bpc,enum hdmi_colorspace fmt)247 hdmi_try_format_bpc(const struct drm_connector *connector,
248 		    struct drm_connector_state *conn_state,
249 		    const struct drm_display_mode *mode,
250 		    unsigned int bpc, enum hdmi_colorspace fmt)
251 {
252 	const struct drm_display_info *info = &connector->display_info;
253 	struct drm_device *dev = connector->dev;
254 	int ret;
255 
256 	drm_dbg_kms(dev, "Trying %s output format\n",
257 		    drm_hdmi_connector_get_output_format_name(fmt));
258 
259 	if (!sink_supports_format_bpc(connector, info, mode, fmt, bpc)) {
260 		drm_dbg_kms(dev, "%s output format not supported with %u bpc\n",
261 			    drm_hdmi_connector_get_output_format_name(fmt),
262 			    bpc);
263 		return false;
264 	}
265 
266 	ret = hdmi_compute_clock(connector, conn_state, mode, bpc, fmt);
267 	if (ret) {
268 		drm_dbg_kms(dev, "Couldn't compute clock for %s output format and %u bpc\n",
269 			    drm_hdmi_connector_get_output_format_name(fmt),
270 			    bpc);
271 		return false;
272 	}
273 
274 	drm_dbg_kms(dev, "%s output format supported with %u (TMDS char rate: %llu Hz)\n",
275 		    drm_hdmi_connector_get_output_format_name(fmt),
276 		    bpc, conn_state->hdmi.tmds_char_rate);
277 
278 	return true;
279 }
280 
281 static int
hdmi_compute_format(const struct drm_connector * connector,struct drm_connector_state * conn_state,const struct drm_display_mode * mode,unsigned int bpc)282 hdmi_compute_format(const struct drm_connector *connector,
283 		    struct drm_connector_state *conn_state,
284 		    const struct drm_display_mode *mode,
285 		    unsigned int bpc)
286 {
287 	struct drm_device *dev = connector->dev;
288 
289 	/*
290 	 * TODO: Add support for YCbCr420 output for HDMI 2.0 capable
291 	 * devices, for modes that only support YCbCr420.
292 	 */
293 	if (hdmi_try_format_bpc(connector, conn_state, mode, bpc, HDMI_COLORSPACE_RGB)) {
294 		conn_state->hdmi.output_format = HDMI_COLORSPACE_RGB;
295 		return 0;
296 	}
297 
298 	drm_dbg_kms(dev, "Failed. No Format Supported for that bpc count.\n");
299 
300 	return -EINVAL;
301 }
302 
303 static int
hdmi_compute_config(const struct drm_connector * connector,struct drm_connector_state * conn_state,const struct drm_display_mode * mode)304 hdmi_compute_config(const struct drm_connector *connector,
305 		    struct drm_connector_state *conn_state,
306 		    const struct drm_display_mode *mode)
307 {
308 	struct drm_device *dev = connector->dev;
309 	unsigned int max_bpc = clamp_t(unsigned int,
310 				       conn_state->max_bpc,
311 				       8, connector->max_bpc);
312 	unsigned int bpc;
313 	int ret;
314 
315 	for (bpc = max_bpc; bpc >= 8; bpc -= 2) {
316 		drm_dbg_kms(dev, "Trying with a %d bpc output\n", bpc);
317 
318 		ret = hdmi_compute_format(connector, conn_state, mode, bpc);
319 		if (ret)
320 			continue;
321 
322 		conn_state->hdmi.output_bpc = bpc;
323 
324 		drm_dbg_kms(dev,
325 			    "Mode %ux%u @ %uHz: Found configuration: bpc: %u, fmt: %s, clock: %llu\n",
326 			    mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode),
327 			    conn_state->hdmi.output_bpc,
328 			    drm_hdmi_connector_get_output_format_name(conn_state->hdmi.output_format),
329 			    conn_state->hdmi.tmds_char_rate);
330 
331 		return 0;
332 	}
333 
334 	return -EINVAL;
335 }
336 
hdmi_generate_avi_infoframe(const struct drm_connector * connector,struct drm_connector_state * conn_state)337 static int hdmi_generate_avi_infoframe(const struct drm_connector *connector,
338 				       struct drm_connector_state *conn_state)
339 {
340 	const struct drm_display_mode *mode =
341 		connector_state_get_mode(conn_state);
342 	struct drm_connector_hdmi_infoframe *infoframe =
343 		&conn_state->hdmi.infoframes.avi;
344 	struct hdmi_avi_infoframe *frame =
345 		&infoframe->data.avi;
346 	bool is_limited_range = conn_state->hdmi.is_limited_range;
347 	enum hdmi_quantization_range rgb_quant_range =
348 		is_limited_range ? HDMI_QUANTIZATION_RANGE_LIMITED : HDMI_QUANTIZATION_RANGE_FULL;
349 	int ret;
350 
351 	infoframe->set = false;
352 
353 	ret = drm_hdmi_avi_infoframe_from_display_mode(frame, connector, mode);
354 	if (ret)
355 		return ret;
356 
357 	frame->colorspace = conn_state->hdmi.output_format;
358 
359 	/*
360 	 * FIXME: drm_hdmi_avi_infoframe_quant_range() doesn't handle
361 	 * YUV formats at all at the moment, so if we ever support YUV
362 	 * formats this needs to be revised.
363 	 */
364 	drm_hdmi_avi_infoframe_quant_range(frame, connector, mode, rgb_quant_range);
365 	drm_hdmi_avi_infoframe_colorimetry(frame, conn_state);
366 	drm_hdmi_avi_infoframe_bars(frame, conn_state);
367 
368 	infoframe->set = true;
369 
370 	return 0;
371 }
372 
hdmi_generate_spd_infoframe(const struct drm_connector * connector,struct drm_connector_state * conn_state)373 static int hdmi_generate_spd_infoframe(const struct drm_connector *connector,
374 				       struct drm_connector_state *conn_state)
375 {
376 	struct drm_connector_hdmi_infoframe *infoframe =
377 		&conn_state->hdmi.infoframes.spd;
378 	struct hdmi_spd_infoframe *frame =
379 		&infoframe->data.spd;
380 	int ret;
381 
382 	infoframe->set = false;
383 
384 	ret = hdmi_spd_infoframe_init(frame,
385 				      connector->hdmi.vendor,
386 				      connector->hdmi.product);
387 	if (ret)
388 		return ret;
389 
390 	frame->sdi = HDMI_SPD_SDI_PC;
391 
392 	infoframe->set = true;
393 
394 	return 0;
395 }
396 
hdmi_generate_hdr_infoframe(const struct drm_connector * connector,struct drm_connector_state * conn_state)397 static int hdmi_generate_hdr_infoframe(const struct drm_connector *connector,
398 				       struct drm_connector_state *conn_state)
399 {
400 	struct drm_connector_hdmi_infoframe *infoframe =
401 		&conn_state->hdmi.infoframes.hdr_drm;
402 	struct hdmi_drm_infoframe *frame =
403 		&infoframe->data.drm;
404 	int ret;
405 
406 	infoframe->set = false;
407 
408 	if (connector->max_bpc < 10)
409 		return 0;
410 
411 	if (!conn_state->hdr_output_metadata)
412 		return 0;
413 
414 	ret = drm_hdmi_infoframe_set_hdr_metadata(frame, conn_state);
415 	if (ret)
416 		return ret;
417 
418 	infoframe->set = true;
419 
420 	return 0;
421 }
422 
hdmi_generate_hdmi_vendor_infoframe(const struct drm_connector * connector,struct drm_connector_state * conn_state)423 static int hdmi_generate_hdmi_vendor_infoframe(const struct drm_connector *connector,
424 					       struct drm_connector_state *conn_state)
425 {
426 	const struct drm_display_info *info = &connector->display_info;
427 	const struct drm_display_mode *mode =
428 		connector_state_get_mode(conn_state);
429 	struct drm_connector_hdmi_infoframe *infoframe =
430 		&conn_state->hdmi.infoframes.hdmi;
431 	struct hdmi_vendor_infoframe *frame =
432 		&infoframe->data.vendor.hdmi;
433 	int ret;
434 
435 	infoframe->set = false;
436 
437 	if (!info->has_hdmi_infoframe)
438 		return 0;
439 
440 	ret = drm_hdmi_vendor_infoframe_from_display_mode(frame, connector, mode);
441 	if (ret)
442 		return ret;
443 
444 	infoframe->set = true;
445 
446 	return 0;
447 }
448 
449 static int
hdmi_generate_infoframes(const struct drm_connector * connector,struct drm_connector_state * conn_state)450 hdmi_generate_infoframes(const struct drm_connector *connector,
451 			 struct drm_connector_state *conn_state)
452 {
453 	const struct drm_display_info *info = &connector->display_info;
454 	int ret;
455 
456 	if (!info->is_hdmi)
457 		return 0;
458 
459 	ret = hdmi_generate_avi_infoframe(connector, conn_state);
460 	if (ret)
461 		return ret;
462 
463 	ret = hdmi_generate_spd_infoframe(connector, conn_state);
464 	if (ret)
465 		return ret;
466 
467 	/*
468 	 * Audio Infoframes will be generated by ALSA, and updated by
469 	 * drm_atomic_helper_connector_hdmi_update_audio_infoframe().
470 	 */
471 
472 	ret = hdmi_generate_hdr_infoframe(connector, conn_state);
473 	if (ret)
474 		return ret;
475 
476 	ret = hdmi_generate_hdmi_vendor_infoframe(connector, conn_state);
477 	if (ret)
478 		return ret;
479 
480 	return 0;
481 }
482 
483 /**
484  * drm_atomic_helper_connector_hdmi_check() - Helper to check HDMI connector atomic state
485  * @connector: DRM Connector
486  * @state: the DRM State object
487  *
488  * Provides a default connector state check handler for HDMI connectors.
489  * Checks that a desired connector update is valid, and updates various
490  * fields of derived state.
491  *
492  * RETURNS:
493  * Zero on success, or an errno code otherwise.
494  */
drm_atomic_helper_connector_hdmi_check(struct drm_connector * connector,struct drm_atomic_state * state)495 int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector,
496 					   struct drm_atomic_state *state)
497 {
498 	struct drm_connector_state *old_conn_state =
499 		drm_atomic_get_old_connector_state(state, connector);
500 	struct drm_connector_state *new_conn_state =
501 		drm_atomic_get_new_connector_state(state, connector);
502 	const struct drm_display_mode *mode =
503 		connector_state_get_mode(new_conn_state);
504 	int ret;
505 
506 	if (!new_conn_state->crtc || !new_conn_state->best_encoder)
507 		return 0;
508 
509 	new_conn_state->hdmi.is_limited_range = hdmi_is_limited_range(connector, new_conn_state);
510 
511 	ret = hdmi_compute_config(connector, new_conn_state, mode);
512 	if (ret)
513 		return ret;
514 
515 	ret = hdmi_generate_infoframes(connector, new_conn_state);
516 	if (ret)
517 		return ret;
518 
519 	if (old_conn_state->hdmi.broadcast_rgb != new_conn_state->hdmi.broadcast_rgb ||
520 	    old_conn_state->hdmi.output_bpc != new_conn_state->hdmi.output_bpc ||
521 	    old_conn_state->hdmi.output_format != new_conn_state->hdmi.output_format) {
522 		struct drm_crtc *crtc = new_conn_state->crtc;
523 		struct drm_crtc_state *crtc_state;
524 
525 		crtc_state = drm_atomic_get_crtc_state(state, crtc);
526 		if (IS_ERR(crtc_state))
527 			return PTR_ERR(crtc_state);
528 
529 		crtc_state->mode_changed = true;
530 	}
531 
532 	return 0;
533 }
534 EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_check);
535 
536 /**
537  * drm_hdmi_connector_mode_valid() - Check if mode is valid for HDMI connector
538  * @connector: DRM connector to validate the mode
539  * @mode: Display mode to validate
540  *
541  * Generic .mode_valid implementation for HDMI connectors.
542  */
543 enum drm_mode_status
drm_hdmi_connector_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)544 drm_hdmi_connector_mode_valid(struct drm_connector *connector,
545 			      struct drm_display_mode *mode)
546 {
547 	unsigned long long clock;
548 
549 	clock = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB);
550 	if (!clock)
551 		return MODE_ERROR;
552 
553 	return hdmi_clock_valid(connector, mode, clock);
554 }
555 EXPORT_SYMBOL(drm_hdmi_connector_mode_valid);
556 
clear_device_infoframe(struct drm_connector * connector,enum hdmi_infoframe_type type)557 static int clear_device_infoframe(struct drm_connector *connector,
558 				  enum hdmi_infoframe_type type)
559 {
560 	const struct drm_connector_hdmi_funcs *funcs = connector->hdmi.funcs;
561 	struct drm_device *dev = connector->dev;
562 	int ret;
563 
564 	drm_dbg_kms(dev, "Clearing infoframe type 0x%x\n", type);
565 
566 	if (!funcs || !funcs->clear_infoframe) {
567 		drm_dbg_kms(dev, "Function not implemented, bailing.\n");
568 		return 0;
569 	}
570 
571 	ret = funcs->clear_infoframe(connector, type);
572 	if (ret) {
573 		drm_dbg_kms(dev, "Call failed: %d\n", ret);
574 		return ret;
575 	}
576 
577 	return 0;
578 }
579 
clear_infoframe(struct drm_connector * connector,struct drm_connector_hdmi_infoframe * old_frame)580 static int clear_infoframe(struct drm_connector *connector,
581 			   struct drm_connector_hdmi_infoframe *old_frame)
582 {
583 	int ret;
584 
585 	ret = clear_device_infoframe(connector, old_frame->data.any.type);
586 	if (ret)
587 		return ret;
588 
589 	return 0;
590 }
591 
write_device_infoframe(struct drm_connector * connector,union hdmi_infoframe * frame)592 static int write_device_infoframe(struct drm_connector *connector,
593 				  union hdmi_infoframe *frame)
594 {
595 	const struct drm_connector_hdmi_funcs *funcs = connector->hdmi.funcs;
596 	struct drm_device *dev = connector->dev;
597 	u8 buffer[HDMI_INFOFRAME_SIZE(MAX)];
598 	int ret;
599 	int len;
600 
601 	drm_dbg_kms(dev, "Writing infoframe type %x\n", frame->any.type);
602 
603 	if (!funcs || !funcs->write_infoframe) {
604 		drm_dbg_kms(dev, "Function not implemented, bailing.\n");
605 		return -EINVAL;
606 	}
607 
608 	len = hdmi_infoframe_pack(frame, buffer, sizeof(buffer));
609 	if (len < 0)
610 		return len;
611 
612 	ret = funcs->write_infoframe(connector, frame->any.type, buffer, len);
613 	if (ret) {
614 		drm_dbg_kms(dev, "Call failed: %d\n", ret);
615 		return ret;
616 	}
617 
618 	return 0;
619 }
620 
write_infoframe(struct drm_connector * connector,struct drm_connector_hdmi_infoframe * new_frame)621 static int write_infoframe(struct drm_connector *connector,
622 			   struct drm_connector_hdmi_infoframe *new_frame)
623 {
624 	int ret;
625 
626 	ret = write_device_infoframe(connector, &new_frame->data);
627 	if (ret)
628 		return ret;
629 
630 	return 0;
631 }
632 
write_or_clear_infoframe(struct drm_connector * connector,struct drm_connector_hdmi_infoframe * old_frame,struct drm_connector_hdmi_infoframe * new_frame)633 static int write_or_clear_infoframe(struct drm_connector *connector,
634 				    struct drm_connector_hdmi_infoframe *old_frame,
635 				    struct drm_connector_hdmi_infoframe *new_frame)
636 {
637 	if (new_frame->set)
638 		return write_infoframe(connector, new_frame);
639 
640 	if (old_frame->set && !new_frame->set)
641 		return clear_infoframe(connector, old_frame);
642 
643 	return 0;
644 }
645 
646 /**
647  * drm_atomic_helper_connector_hdmi_update_infoframes - Update the Infoframes
648  * @connector: A pointer to the HDMI connector
649  * @state: The HDMI connector state to generate the infoframe from
650  *
651  * This function is meant for HDMI connector drivers to write their
652  * infoframes. It will typically be used in a
653  * @drm_connector_helper_funcs.atomic_enable implementation.
654  *
655  * Returns:
656  * Zero on success, error code on failure.
657  */
drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector * connector,struct drm_atomic_state * state)658 int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *connector,
659 						       struct drm_atomic_state *state)
660 {
661 	struct drm_connector_state *old_conn_state =
662 		drm_atomic_get_old_connector_state(state, connector);
663 	struct drm_connector_state *new_conn_state =
664 		drm_atomic_get_new_connector_state(state, connector);
665 	struct drm_display_info *info = &connector->display_info;
666 	int ret;
667 
668 	if (!info->is_hdmi)
669 		return 0;
670 
671 	mutex_lock(&connector->hdmi.infoframes.lock);
672 
673 	ret = write_or_clear_infoframe(connector,
674 				       &old_conn_state->hdmi.infoframes.avi,
675 				       &new_conn_state->hdmi.infoframes.avi);
676 	if (ret)
677 		goto out;
678 
679 	if (connector->hdmi.infoframes.audio.set) {
680 		ret = write_infoframe(connector,
681 				      &connector->hdmi.infoframes.audio);
682 		if (ret)
683 			goto out;
684 	}
685 
686 	ret = write_or_clear_infoframe(connector,
687 				       &old_conn_state->hdmi.infoframes.hdr_drm,
688 				       &new_conn_state->hdmi.infoframes.hdr_drm);
689 	if (ret)
690 		goto out;
691 
692 	ret = write_or_clear_infoframe(connector,
693 				       &old_conn_state->hdmi.infoframes.spd,
694 				       &new_conn_state->hdmi.infoframes.spd);
695 	if (ret)
696 		goto out;
697 
698 	if (info->has_hdmi_infoframe) {
699 		ret = write_or_clear_infoframe(connector,
700 					       &old_conn_state->hdmi.infoframes.hdmi,
701 					       &new_conn_state->hdmi.infoframes.hdmi);
702 		if (ret)
703 			goto out;
704 	}
705 
706 out:
707 	mutex_unlock(&connector->hdmi.infoframes.lock);
708 	return ret;
709 }
710 EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_update_infoframes);
711 
712 /**
713  * drm_atomic_helper_connector_hdmi_update_audio_infoframe - Update the Audio Infoframe
714  * @connector: A pointer to the HDMI connector
715  * @frame: A pointer to the audio infoframe to write
716  *
717  * This function is meant for HDMI connector drivers to update their
718  * audio infoframe. It will typically be used in one of the ALSA hooks
719  * (most likely prepare).
720  *
721  * Returns:
722  * Zero on success, error code on failure.
723  */
724 int
drm_atomic_helper_connector_hdmi_update_audio_infoframe(struct drm_connector * connector,struct hdmi_audio_infoframe * frame)725 drm_atomic_helper_connector_hdmi_update_audio_infoframe(struct drm_connector *connector,
726 							struct hdmi_audio_infoframe *frame)
727 {
728 	struct drm_connector_hdmi_infoframe *infoframe =
729 		&connector->hdmi.infoframes.audio;
730 	struct drm_display_info *info = &connector->display_info;
731 	int ret;
732 
733 	if (!info->is_hdmi)
734 		return 0;
735 
736 	mutex_lock(&connector->hdmi.infoframes.lock);
737 
738 	memcpy(&infoframe->data, frame, sizeof(infoframe->data));
739 	infoframe->set = true;
740 
741 	ret = write_infoframe(connector, infoframe);
742 
743 	mutex_unlock(&connector->hdmi.infoframes.lock);
744 
745 	return ret;
746 }
747 EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_update_audio_infoframe);
748 
749 /**
750  * drm_atomic_helper_connector_hdmi_clear_audio_infoframe - Stop sending the Audio Infoframe
751  * @connector: A pointer to the HDMI connector
752  *
753  * This function is meant for HDMI connector drivers to stop sending their
754  * audio infoframe. It will typically be used in one of the ALSA hooks
755  * (most likely shutdown).
756  *
757  * Returns:
758  * Zero on success, error code on failure.
759  */
760 int
drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector * connector)761 drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector *connector)
762 {
763 	struct drm_connector_hdmi_infoframe *infoframe =
764 		&connector->hdmi.infoframes.audio;
765 	struct drm_display_info *info = &connector->display_info;
766 	int ret;
767 
768 	if (!info->is_hdmi)
769 		return 0;
770 
771 	mutex_lock(&connector->hdmi.infoframes.lock);
772 
773 	infoframe->set = false;
774 
775 	ret = clear_infoframe(connector, infoframe);
776 
777 	memset(&infoframe->data, 0, sizeof(infoframe->data));
778 
779 	mutex_unlock(&connector->hdmi.infoframes.lock);
780 
781 	return ret;
782 }
783 EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_clear_audio_infoframe);
784 
785 static void
drm_atomic_helper_connector_hdmi_update(struct drm_connector * connector,enum drm_connector_status status)786 drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
787 					enum drm_connector_status status)
788 {
789 	const struct drm_edid *drm_edid;
790 
791 	if (status == connector_status_disconnected) {
792 		// TODO: also handle CEC and scramber, HDMI sink disconnected.
793 		drm_connector_hdmi_audio_plugged_notify(connector, false);
794 		drm_edid_connector_update(connector, NULL);
795 		return;
796 	}
797 
798 	if (connector->hdmi.funcs->read_edid)
799 		drm_edid = connector->hdmi.funcs->read_edid(connector);
800 	else
801 		drm_edid = drm_edid_read(connector);
802 
803 	drm_edid_connector_update(connector, drm_edid);
804 
805 	drm_edid_free(drm_edid);
806 
807 	if (status == connector_status_connected) {
808 		// TODO: also handle CEC and scramber, HDMI sink is now connected.
809 		drm_connector_hdmi_audio_plugged_notify(connector, true);
810 	}
811 }
812 
813 /**
814  * drm_atomic_helper_connector_hdmi_hotplug - Handle the hotplug event for the HDMI connector
815  * @connector: A pointer to the HDMI connector
816  * @status: Connection status
817  *
818  * This function should be called as a part of the .detect() / .detect_ctx()
819  * callbacks, updating the HDMI-specific connector's data.
820  */
drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector * connector,enum drm_connector_status status)821 void drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
822 					      enum drm_connector_status status)
823 {
824 	drm_atomic_helper_connector_hdmi_update(connector, status);
825 }
826 EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug);
827 
828 /**
829  * drm_atomic_helper_connector_hdmi_force - HDMI Connector implementation of the force callback
830  * @connector: A pointer to the HDMI connector
831  *
832  * This function implements the .force() callback for the HDMI connectors. It
833  * can either be used directly as the callback or should be called from within
834  * the .force() callback implementation to maintain the HDMI-specific
835  * connector's data.
836  */
drm_atomic_helper_connector_hdmi_force(struct drm_connector * connector)837 void drm_atomic_helper_connector_hdmi_force(struct drm_connector *connector)
838 {
839 	drm_atomic_helper_connector_hdmi_update(connector, connector->status);
840 }
841 EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_force);
842