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