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 */
__drm_atomic_helper_connector_hdmi_reset(struct drm_connector * connector,struct drm_connector_state * new_conn_state)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 *
connector_state_get_mode(const struct drm_connector_state * conn_state)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
hdmi_is_limited_range(const struct drm_connector * connector,const struct drm_connector_state * conn_state)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
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)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
hdmi_clock_valid(const struct drm_connector * connector,const struct drm_display_mode * mode,unsigned long long clock)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
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)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
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)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
hdmi_compute_format(const struct drm_connector * connector,struct drm_connector_state * conn_state,const struct drm_display_mode * mode,unsigned int bpc)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
hdmi_compute_config(const struct drm_connector * connector,struct drm_connector_state * conn_state,const struct drm_display_mode * mode)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
hdmi_generate_avi_infoframe(const struct drm_connector * connector,struct drm_connector_state * conn_state)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 ret = drm_hdmi_avi_infoframe_from_display_mode(frame, connector, mode);
351 if (ret)
352 return ret;
353
354 frame->colorspace = conn_state->hdmi.output_format;
355
356 /*
357 * FIXME: drm_hdmi_avi_infoframe_quant_range() doesn't handle
358 * YUV formats at all at the moment, so if we ever support YUV
359 * formats this needs to be revised.
360 */
361 drm_hdmi_avi_infoframe_quant_range(frame, connector, mode, rgb_quant_range);
362 drm_hdmi_avi_infoframe_colorimetry(frame, conn_state);
363 drm_hdmi_avi_infoframe_bars(frame, conn_state);
364
365 infoframe->set = true;
366
367 return 0;
368 }
369
hdmi_generate_spd_infoframe(const struct drm_connector * connector,struct drm_connector_state * conn_state)370 static int hdmi_generate_spd_infoframe(const struct drm_connector *connector,
371 struct drm_connector_state *conn_state)
372 {
373 struct drm_connector_hdmi_infoframe *infoframe =
374 &conn_state->hdmi.infoframes.spd;
375 struct hdmi_spd_infoframe *frame =
376 &infoframe->data.spd;
377 int ret;
378
379 ret = hdmi_spd_infoframe_init(frame,
380 connector->hdmi.vendor,
381 connector->hdmi.product);
382 if (ret)
383 return ret;
384
385 frame->sdi = HDMI_SPD_SDI_PC;
386
387 infoframe->set = true;
388
389 return 0;
390 }
391
hdmi_generate_hdr_infoframe(const struct drm_connector * connector,struct drm_connector_state * conn_state)392 static int hdmi_generate_hdr_infoframe(const struct drm_connector *connector,
393 struct drm_connector_state *conn_state)
394 {
395 struct drm_connector_hdmi_infoframe *infoframe =
396 &conn_state->hdmi.infoframes.hdr_drm;
397 struct hdmi_drm_infoframe *frame =
398 &infoframe->data.drm;
399 int ret;
400
401 if (connector->max_bpc < 10)
402 return 0;
403
404 if (!conn_state->hdr_output_metadata)
405 return 0;
406
407 ret = drm_hdmi_infoframe_set_hdr_metadata(frame, conn_state);
408 if (ret)
409 return ret;
410
411 infoframe->set = true;
412
413 return 0;
414 }
415
hdmi_generate_hdmi_vendor_infoframe(const struct drm_connector * connector,struct drm_connector_state * conn_state)416 static int hdmi_generate_hdmi_vendor_infoframe(const struct drm_connector *connector,
417 struct drm_connector_state *conn_state)
418 {
419 const struct drm_display_info *info = &connector->display_info;
420 const struct drm_display_mode *mode =
421 connector_state_get_mode(conn_state);
422 struct drm_connector_hdmi_infoframe *infoframe =
423 &conn_state->hdmi.infoframes.hdmi;
424 struct hdmi_vendor_infoframe *frame =
425 &infoframe->data.vendor.hdmi;
426 int ret;
427
428 if (!info->has_hdmi_infoframe)
429 return 0;
430
431 ret = drm_hdmi_vendor_infoframe_from_display_mode(frame, connector, mode);
432 if (ret)
433 return ret;
434
435 infoframe->set = true;
436
437 return 0;
438 }
439
440 static int
hdmi_generate_infoframes(const struct drm_connector * connector,struct drm_connector_state * conn_state)441 hdmi_generate_infoframes(const struct drm_connector *connector,
442 struct drm_connector_state *conn_state)
443 {
444 const struct drm_display_info *info = &connector->display_info;
445 int ret;
446
447 if (!info->is_hdmi)
448 return 0;
449
450 ret = hdmi_generate_avi_infoframe(connector, conn_state);
451 if (ret)
452 return ret;
453
454 ret = hdmi_generate_spd_infoframe(connector, conn_state);
455 if (ret)
456 return ret;
457
458 /*
459 * Audio Infoframes will be generated by ALSA, and updated by
460 * drm_atomic_helper_connector_hdmi_update_audio_infoframe().
461 */
462
463 ret = hdmi_generate_hdr_infoframe(connector, conn_state);
464 if (ret)
465 return ret;
466
467 ret = hdmi_generate_hdmi_vendor_infoframe(connector, conn_state);
468 if (ret)
469 return ret;
470
471 return 0;
472 }
473
474 /**
475 * drm_atomic_helper_connector_hdmi_check() - Helper to check HDMI connector atomic state
476 * @connector: DRM Connector
477 * @state: the DRM State object
478 *
479 * Provides a default connector state check handler for HDMI connectors.
480 * Checks that a desired connector update is valid, and updates various
481 * fields of derived state.
482 *
483 * RETURNS:
484 * Zero on success, or an errno code otherwise.
485 */
drm_atomic_helper_connector_hdmi_check(struct drm_connector * connector,struct drm_atomic_state * state)486 int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector,
487 struct drm_atomic_state *state)
488 {
489 struct drm_connector_state *old_conn_state =
490 drm_atomic_get_old_connector_state(state, connector);
491 struct drm_connector_state *new_conn_state =
492 drm_atomic_get_new_connector_state(state, connector);
493 const struct drm_display_mode *mode =
494 connector_state_get_mode(new_conn_state);
495 int ret;
496
497 new_conn_state->hdmi.is_limited_range = hdmi_is_limited_range(connector, new_conn_state);
498
499 ret = hdmi_compute_config(connector, new_conn_state, mode);
500 if (ret)
501 return ret;
502
503 ret = hdmi_generate_infoframes(connector, new_conn_state);
504 if (ret)
505 return ret;
506
507 if (old_conn_state->hdmi.broadcast_rgb != new_conn_state->hdmi.broadcast_rgb ||
508 old_conn_state->hdmi.output_bpc != new_conn_state->hdmi.output_bpc ||
509 old_conn_state->hdmi.output_format != new_conn_state->hdmi.output_format) {
510 struct drm_crtc *crtc = new_conn_state->crtc;
511 struct drm_crtc_state *crtc_state;
512
513 crtc_state = drm_atomic_get_crtc_state(state, crtc);
514 if (IS_ERR(crtc_state))
515 return PTR_ERR(crtc_state);
516
517 crtc_state->mode_changed = true;
518 }
519
520 return 0;
521 }
522 EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_check);
523
clear_device_infoframe(struct drm_connector * connector,enum hdmi_infoframe_type type)524 static int clear_device_infoframe(struct drm_connector *connector,
525 enum hdmi_infoframe_type type)
526 {
527 const struct drm_connector_hdmi_funcs *funcs = connector->hdmi.funcs;
528 struct drm_device *dev = connector->dev;
529 int ret;
530
531 drm_dbg_kms(dev, "Clearing infoframe type 0x%x\n", type);
532
533 if (!funcs || !funcs->clear_infoframe) {
534 drm_dbg_kms(dev, "Function not implemented, bailing.\n");
535 return 0;
536 }
537
538 ret = funcs->clear_infoframe(connector, type);
539 if (ret) {
540 drm_dbg_kms(dev, "Call failed: %d\n", ret);
541 return ret;
542 }
543
544 return 0;
545 }
546
clear_infoframe(struct drm_connector * connector,struct drm_connector_hdmi_infoframe * old_frame)547 static int clear_infoframe(struct drm_connector *connector,
548 struct drm_connector_hdmi_infoframe *old_frame)
549 {
550 int ret;
551
552 ret = clear_device_infoframe(connector, old_frame->data.any.type);
553 if (ret)
554 return ret;
555
556 return 0;
557 }
558
write_device_infoframe(struct drm_connector * connector,union hdmi_infoframe * frame)559 static int write_device_infoframe(struct drm_connector *connector,
560 union hdmi_infoframe *frame)
561 {
562 const struct drm_connector_hdmi_funcs *funcs = connector->hdmi.funcs;
563 struct drm_device *dev = connector->dev;
564 u8 buffer[HDMI_INFOFRAME_SIZE(MAX)];
565 int ret;
566 int len;
567
568 drm_dbg_kms(dev, "Writing infoframe type %x\n", frame->any.type);
569
570 if (!funcs || !funcs->write_infoframe) {
571 drm_dbg_kms(dev, "Function not implemented, bailing.\n");
572 return -EINVAL;
573 }
574
575 len = hdmi_infoframe_pack(frame, buffer, sizeof(buffer));
576 if (len < 0)
577 return len;
578
579 ret = funcs->write_infoframe(connector, frame->any.type, buffer, len);
580 if (ret) {
581 drm_dbg_kms(dev, "Call failed: %d\n", ret);
582 return ret;
583 }
584
585 return 0;
586 }
587
write_infoframe(struct drm_connector * connector,struct drm_connector_hdmi_infoframe * new_frame)588 static int write_infoframe(struct drm_connector *connector,
589 struct drm_connector_hdmi_infoframe *new_frame)
590 {
591 int ret;
592
593 ret = write_device_infoframe(connector, &new_frame->data);
594 if (ret)
595 return ret;
596
597 return 0;
598 }
599
write_or_clear_infoframe(struct drm_connector * connector,struct drm_connector_hdmi_infoframe * old_frame,struct drm_connector_hdmi_infoframe * new_frame)600 static int write_or_clear_infoframe(struct drm_connector *connector,
601 struct drm_connector_hdmi_infoframe *old_frame,
602 struct drm_connector_hdmi_infoframe *new_frame)
603 {
604 if (new_frame->set)
605 return write_infoframe(connector, new_frame);
606
607 if (old_frame->set && !new_frame->set)
608 return clear_infoframe(connector, old_frame);
609
610 return 0;
611 }
612
613 /**
614 * drm_atomic_helper_connector_hdmi_update_infoframes - Update the Infoframes
615 * @connector: A pointer to the HDMI connector
616 * @state: The HDMI connector state to generate the infoframe from
617 *
618 * This function is meant for HDMI connector drivers to write their
619 * infoframes. It will typically be used in a
620 * @drm_connector_helper_funcs.atomic_enable implementation.
621 *
622 * Returns:
623 * Zero on success, error code on failure.
624 */
drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector * connector,struct drm_atomic_state * state)625 int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *connector,
626 struct drm_atomic_state *state)
627 {
628 struct drm_connector_state *old_conn_state =
629 drm_atomic_get_old_connector_state(state, connector);
630 struct drm_connector_state *new_conn_state =
631 drm_atomic_get_new_connector_state(state, connector);
632 struct drm_display_info *info = &connector->display_info;
633 int ret;
634
635 if (!info->is_hdmi)
636 return 0;
637
638 mutex_lock(&connector->hdmi.infoframes.lock);
639
640 ret = write_or_clear_infoframe(connector,
641 &old_conn_state->hdmi.infoframes.avi,
642 &new_conn_state->hdmi.infoframes.avi);
643 if (ret)
644 goto out;
645
646 if (connector->hdmi.infoframes.audio.set) {
647 ret = write_infoframe(connector,
648 &connector->hdmi.infoframes.audio);
649 if (ret)
650 goto out;
651 }
652
653 ret = write_or_clear_infoframe(connector,
654 &old_conn_state->hdmi.infoframes.hdr_drm,
655 &new_conn_state->hdmi.infoframes.hdr_drm);
656 if (ret)
657 goto out;
658
659 ret = write_or_clear_infoframe(connector,
660 &old_conn_state->hdmi.infoframes.spd,
661 &new_conn_state->hdmi.infoframes.spd);
662 if (ret)
663 goto out;
664
665 if (info->has_hdmi_infoframe) {
666 ret = write_or_clear_infoframe(connector,
667 &old_conn_state->hdmi.infoframes.hdmi,
668 &new_conn_state->hdmi.infoframes.hdmi);
669 if (ret)
670 goto out;
671 }
672
673 out:
674 mutex_unlock(&connector->hdmi.infoframes.lock);
675 return ret;
676 }
677 EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_update_infoframes);
678
679 /**
680 * drm_atomic_helper_connector_hdmi_update_audio_infoframe - Update the Audio Infoframe
681 * @connector: A pointer to the HDMI connector
682 * @frame: A pointer to the audio infoframe to write
683 *
684 * This function is meant for HDMI connector drivers to update their
685 * audio infoframe. It will typically be used in one of the ALSA hooks
686 * (most likely prepare).
687 *
688 * Returns:
689 * Zero on success, error code on failure.
690 */
691 int
drm_atomic_helper_connector_hdmi_update_audio_infoframe(struct drm_connector * connector,struct hdmi_audio_infoframe * frame)692 drm_atomic_helper_connector_hdmi_update_audio_infoframe(struct drm_connector *connector,
693 struct hdmi_audio_infoframe *frame)
694 {
695 struct drm_connector_hdmi_infoframe *infoframe =
696 &connector->hdmi.infoframes.audio;
697 struct drm_display_info *info = &connector->display_info;
698 int ret;
699
700 if (!info->is_hdmi)
701 return 0;
702
703 mutex_lock(&connector->hdmi.infoframes.lock);
704
705 memcpy(&infoframe->data, frame, sizeof(infoframe->data));
706 infoframe->set = true;
707
708 ret = write_infoframe(connector, infoframe);
709
710 mutex_unlock(&connector->hdmi.infoframes.lock);
711
712 return ret;
713 }
714 EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_update_audio_infoframe);
715
716 /**
717 * drm_atomic_helper_connector_hdmi_clear_audio_infoframe - Stop sending the Audio Infoframe
718 * @connector: A pointer to the HDMI connector
719 *
720 * This function is meant for HDMI connector drivers to stop sending their
721 * audio infoframe. It will typically be used in one of the ALSA hooks
722 * (most likely shutdown).
723 *
724 * Returns:
725 * Zero on success, error code on failure.
726 */
727 int
drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector * connector)728 drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector *connector)
729 {
730 struct drm_connector_hdmi_infoframe *infoframe =
731 &connector->hdmi.infoframes.audio;
732 struct drm_display_info *info = &connector->display_info;
733 int ret;
734
735 if (!info->is_hdmi)
736 return 0;
737
738 mutex_lock(&connector->hdmi.infoframes.lock);
739
740 infoframe->set = false;
741
742 ret = clear_infoframe(connector, infoframe);
743
744 memset(&infoframe->data, 0, sizeof(infoframe->data));
745
746 mutex_unlock(&connector->hdmi.infoframes.lock);
747
748 return ret;
749 }
750 EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_clear_audio_infoframe);
751