]> Git Repo - J-linux.git/blob - drivers/gpu/drm/display/drm_hdmi_state_helper.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-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_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         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
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
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
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
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  */
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
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
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
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
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
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  */
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
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
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);
This page took 0.069107 seconds and 4 git commands to generate.