]> Git Repo - linux.git/blob - drivers/gpu/drm/display/drm_hdmi_state_helper.c
Linux 6.14-rc3
[linux.git] / drivers / gpu / drm / display / drm_hdmi_state_helper.c
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  */
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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  */
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
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
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
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
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
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
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  */
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
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
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
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  */
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  */
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);
This page took 0.078929 seconds and 4 git commands to generate.