forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
/
drm_modeset_helper_vtables.h
1427 lines (1374 loc) · 56 KB
/
drm_modeset_helper_vtables.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Copyright © 2006 Keith Packard
* Copyright © 2007-2008 Dave Airlie
* Copyright © 2007-2008 Intel Corporation
* Jesse Barnes <[email protected]>
* Copyright © 2011-2013 Intel Corporation
* Copyright © 2015 Intel Corporation
* Daniel Vetter <[email protected]>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __DRM_MODESET_HELPER_VTABLES_H__
#define __DRM_MODESET_HELPER_VTABLES_H__
#include <drm/drm_crtc.h>
#include <drm/drm_encoder.h>
/**
* DOC: overview
*
* The DRM mode setting helper functions are common code for drivers to use if
* they wish. Drivers are not forced to use this code in their
* implementations but it would be useful if the code they do use at least
* provides a consistent interface and operation to userspace. Therefore it is
* highly recommended to use the provided helpers as much as possible.
*
* Because there is only one pointer per modeset object to hold a vfunc table
* for helper libraries they are by necessity shared among the different
* helpers.
*
* To make this clear all the helper vtables are pulled together in this location here.
*/
enum mode_set_atomic;
struct drm_writeback_connector;
struct drm_writeback_job;
/**
* struct drm_crtc_helper_funcs - helper operations for CRTCs
*
* These hooks are used by the legacy CRTC helpers, the transitional plane
* helpers and the new atomic modesetting helpers.
*/
struct drm_crtc_helper_funcs {
/**
* @dpms:
*
* Callback to control power levels on the CRTC. If the mode passed in
* is unsupported, the provider must use the next lowest power level.
* This is used by the legacy CRTC helpers to implement DPMS
* functionality in drm_helper_connector_dpms().
*
* This callback is also used to disable a CRTC by calling it with
* DRM_MODE_DPMS_OFF if the @disable hook isn't used.
*
* This callback is used by the legacy CRTC helpers. Atomic helpers
* also support using this hook for enabling and disabling a CRTC to
* facilitate transitions to atomic, but it is deprecated. Instead
* @atomic_enable and @atomic_disable should be used.
*/
void (*dpms)(struct drm_crtc *crtc, int mode);
/**
* @prepare:
*
* This callback should prepare the CRTC for a subsequent modeset, which
* in practice means the driver should disable the CRTC if it is
* running. Most drivers ended up implementing this by calling their
* @dpms hook with DRM_MODE_DPMS_OFF.
*
* This callback is used by the legacy CRTC helpers. Atomic helpers
* also support using this hook for disabling a CRTC to facilitate
* transitions to atomic, but it is deprecated. Instead @atomic_disable
* should be used.
*/
void (*prepare)(struct drm_crtc *crtc);
/**
* @commit:
*
* This callback should commit the new mode on the CRTC after a modeset,
* which in practice means the driver should enable the CRTC. Most
* drivers ended up implementing this by calling their @dpms hook with
* DRM_MODE_DPMS_ON.
*
* This callback is used by the legacy CRTC helpers. Atomic helpers
* also support using this hook for enabling a CRTC to facilitate
* transitions to atomic, but it is deprecated. Instead @atomic_enable
* should be used.
*/
void (*commit)(struct drm_crtc *crtc);
/**
* @mode_valid:
*
* This callback is used to check if a specific mode is valid in this
* crtc. This should be implemented if the crtc has some sort of
* restriction in the modes it can display. For example, a given crtc
* may be responsible to set a clock value. If the clock can not
* produce all the values for the available modes then this callback
* can be used to restrict the number of modes to only the ones that
* can be displayed.
*
* This hook is used by the probe helpers to filter the mode list in
* drm_helper_probe_single_connector_modes(), and it is used by the
* atomic helpers to validate modes supplied by userspace in
* drm_atomic_helper_check_modeset().
*
* This function is optional.
*
* NOTE:
*
* Since this function is both called from the check phase of an atomic
* commit, and the mode validation in the probe paths it is not allowed
* to look at anything else but the passed-in mode, and validate it
* against configuration-invariant hardward constraints. Any further
* limits which depend upon the configuration can only be checked in
* @mode_fixup or @atomic_check.
*
* RETURNS:
*
* drm_mode_status Enum
*/
enum drm_mode_status (*mode_valid)(struct drm_crtc *crtc,
const struct drm_display_mode *mode);
/**
* @mode_fixup:
*
* This callback is used to validate a mode. The parameter mode is the
* display mode that userspace requested, adjusted_mode is the mode the
* encoders need to be fed with. Note that this is the inverse semantics
* of the meaning for the &drm_encoder and &drm_bridge_funcs.mode_fixup
* vfunc. If the CRTC cannot support the requested conversion from mode
* to adjusted_mode it should reject the modeset. See also
* &drm_crtc_state.adjusted_mode for more details.
*
* This function is used by both legacy CRTC helpers and atomic helpers.
* With atomic helpers it is optional.
*
* NOTE:
*
* This function is called in the check phase of atomic modesets, which
* can be aborted for any reason (including on userspace's request to
* just check whether a configuration would be possible). Atomic drivers
* MUST NOT touch any persistent state (hardware or software) or data
* structures except the passed in adjusted_mode parameter.
*
* This is in contrast to the legacy CRTC helpers where this was
* allowed.
*
* Atomic drivers which need to inspect and adjust more state should
* instead use the @atomic_check callback, but note that they're not
* perfectly equivalent: @mode_valid is called from
* drm_atomic_helper_check_modeset(), but @atomic_check is called from
* drm_atomic_helper_check_planes(), because originally it was meant for
* plane update checks only.
*
* Also beware that userspace can request its own custom modes, neither
* core nor helpers filter modes to the list of probe modes reported by
* the GETCONNECTOR IOCTL and stored in &drm_connector.modes. To ensure
* that modes are filtered consistently put any CRTC constraints and
* limits checks into @mode_valid.
*
* RETURNS:
*
* True if an acceptable configuration is possible, false if the modeset
* operation should be rejected.
*/
bool (*mode_fixup)(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
/**
* @mode_set:
*
* This callback is used by the legacy CRTC helpers to set a new mode,
* position and framebuffer. Since it ties the primary plane to every
* mode change it is incompatible with universal plane support. And
* since it can't update other planes it's incompatible with atomic
* modeset support.
*
* This callback is only used by CRTC helpers and deprecated.
*
* RETURNS:
*
* 0 on success or a negative error code on failure.
*/
int (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode, int x, int y,
struct drm_framebuffer *old_fb);
/**
* @mode_set_nofb:
*
* This callback is used to update the display mode of a CRTC without
* changing anything of the primary plane configuration. This fits the
* requirement of atomic and hence is used by the atomic helpers. It is
* also used by the transitional plane helpers to implement a
* @mode_set hook in drm_helper_crtc_mode_set().
*
* Note that the display pipe is completely off when this function is
* called. Atomic drivers which need hardware to be running before they
* program the new display mode (e.g. because they implement runtime PM)
* should not use this hook. This is because the helper library calls
* this hook only once per mode change and not every time the display
* pipeline is suspended using either DPMS or the new "ACTIVE" property.
* Which means register values set in this callback might get reset when
* the CRTC is suspended, but not restored. Such drivers should instead
* move all their CRTC setup into the @atomic_enable callback.
*
* This callback is optional.
*/
void (*mode_set_nofb)(struct drm_crtc *crtc);
/**
* @mode_set_base:
*
* This callback is used by the legacy CRTC helpers to set a new
* framebuffer and scanout position. It is optional and used as an
* optimized fast-path instead of a full mode set operation with all the
* resulting flickering. If it is not present
* drm_crtc_helper_set_config() will fall back to a full modeset, using
* the @mode_set callback. Since it can't update other planes it's
* incompatible with atomic modeset support.
*
* This callback is only used by the CRTC helpers and deprecated.
*
* RETURNS:
*
* 0 on success or a negative error code on failure.
*/
int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb);
/**
* @mode_set_base_atomic:
*
* This callback is used by the fbdev helpers to set a new framebuffer
* and scanout without sleeping, i.e. from an atomic calling context. It
* is only used to implement kgdb support.
*
* This callback is optional and only needed for kgdb support in the fbdev
* helpers.
*
* RETURNS:
*
* 0 on success or a negative error code on failure.
*/
int (*mode_set_base_atomic)(struct drm_crtc *crtc,
struct drm_framebuffer *fb, int x, int y,
enum mode_set_atomic);
/**
* @disable:
*
* This callback should be used to disable the CRTC. With the atomic
* drivers it is called after all encoders connected to this CRTC have
* been shut off already using their own
* &drm_encoder_helper_funcs.disable hook. If that sequence is too
* simple drivers can just add their own hooks and call it from this
* CRTC callback here by looping over all encoders connected to it using
* for_each_encoder_on_crtc().
*
* This hook is used both by legacy CRTC helpers and atomic helpers.
* Atomic drivers don't need to implement it if there's no need to
* disable anything at the CRTC level. To ensure that runtime PM
* handling (using either DPMS or the new "ACTIVE" property) works
* @disable must be the inverse of @atomic_enable for atomic drivers.
* Atomic drivers should consider to use @atomic_disable instead of
* this one.
*
* NOTE:
*
* With legacy CRTC helpers there's a big semantic difference between
* @disable and other hooks (like @prepare or @dpms) used to shut down a
* CRTC: @disable is only called when also logically disabling the
* display pipeline and needs to release any resources acquired in
* @mode_set (like shared PLLs, or again release pinned framebuffers).
*
* Therefore @disable must be the inverse of @mode_set plus @commit for
* drivers still using legacy CRTC helpers, which is different from the
* rules under atomic.
*/
void (*disable)(struct drm_crtc *crtc);
/**
* @atomic_check:
*
* Drivers should check plane-update related CRTC constraints in this
* hook. They can also check mode related limitations but need to be
* aware of the calling order, since this hook is used by
* drm_atomic_helper_check_planes() whereas the preparations needed to
* check output routing and the display mode is done in
* drm_atomic_helper_check_modeset(). Therefore drivers that want to
* check output routing and display mode constraints in this callback
* must ensure that drm_atomic_helper_check_modeset() has been called
* beforehand. This is calling order used by the default helper
* implementation in drm_atomic_helper_check().
*
* When using drm_atomic_helper_check_planes() this hook is called
* after the &drm_plane_helper_funcs.atomic_check hook for planes, which
* allows drivers to assign shared resources requested by planes in this
* callback here. For more complicated dependencies the driver can call
* the provided check helpers multiple times until the computed state
* has a final configuration and everything has been checked.
*
* This function is also allowed to inspect any other object's state and
* can add more state objects to the atomic commit if needed. Care must
* be taken though to ensure that state check and compute functions for
* these added states are all called, and derived state in other objects
* all updated. Again the recommendation is to just call check helpers
* until a maximal configuration is reached.
*
* This callback is used by the atomic modeset helpers and by the
* transitional plane helpers, but it is optional.
*
* NOTE:
*
* This function is called in the check phase of an atomic update. The
* driver is not allowed to change anything outside of the free-standing
* state object passed-in.
*
* Also beware that userspace can request its own custom modes, neither
* core nor helpers filter modes to the list of probe modes reported by
* the GETCONNECTOR IOCTL and stored in &drm_connector.modes. To ensure
* that modes are filtered consistently put any CRTC constraints and
* limits checks into @mode_valid.
*
* RETURNS:
*
* 0 on success, -EINVAL if the state or the transition can't be
* supported, -ENOMEM on memory allocation failure and -EDEADLK if an
* attempt to obtain another state object ran into a &drm_modeset_lock
* deadlock.
*/
int (*atomic_check)(struct drm_crtc *crtc,
struct drm_atomic_state *state);
/**
* @atomic_begin:
*
* Drivers should prepare for an atomic update of multiple planes on
* a CRTC in this hook. Depending upon hardware this might be vblank
* evasion, blocking updates by setting bits or doing preparatory work
* for e.g. manual update display.
*
* This hook is called before any plane commit functions are called.
*
* Note that the power state of the display pipe when this function is
* called depends upon the exact helpers and calling sequence the driver
* has picked. See drm_atomic_helper_commit_planes() for a discussion of
* the tradeoffs and variants of plane commit helpers.
*
* This callback is used by the atomic modeset helpers and by the
* transitional plane helpers, but it is optional.
*/
void (*atomic_begin)(struct drm_crtc *crtc,
struct drm_atomic_state *state);
/**
* @atomic_flush:
*
* Drivers should finalize an atomic update of multiple planes on
* a CRTC in this hook. Depending upon hardware this might include
* checking that vblank evasion was successful, unblocking updates by
* setting bits or setting the GO bit to flush out all updates.
*
* Simple hardware or hardware with special requirements can commit and
* flush out all updates for all planes from this hook and forgo all the
* other commit hooks for plane updates.
*
* This hook is called after any plane commit functions are called.
*
* Note that the power state of the display pipe when this function is
* called depends upon the exact helpers and calling sequence the driver
* has picked. See drm_atomic_helper_commit_planes() for a discussion of
* the tradeoffs and variants of plane commit helpers.
*
* This callback is used by the atomic modeset helpers and by the
* transitional plane helpers, but it is optional.
*/
void (*atomic_flush)(struct drm_crtc *crtc,
struct drm_atomic_state *state);
/**
* @atomic_enable:
*
* This callback should be used to enable the CRTC. With the atomic
* drivers it is called before all encoders connected to this CRTC are
* enabled through the encoder's own &drm_encoder_helper_funcs.enable
* hook. If that sequence is too simple drivers can just add their own
* hooks and call it from this CRTC callback here by looping over all
* encoders connected to it using for_each_encoder_on_crtc().
*
* This hook is used only by atomic helpers, for symmetry with
* @atomic_disable. Atomic drivers don't need to implement it if there's
* no need to enable anything at the CRTC level. To ensure that runtime
* PM handling (using either DPMS or the new "ACTIVE" property) works
* @atomic_enable must be the inverse of @atomic_disable for atomic
* drivers.
*
* This function is optional.
*/
void (*atomic_enable)(struct drm_crtc *crtc,
struct drm_atomic_state *state);
/**
* @atomic_disable:
*
* This callback should be used to disable the CRTC. With the atomic
* drivers it is called after all encoders connected to this CRTC have
* been shut off already using their own
* &drm_encoder_helper_funcs.disable hook. If that sequence is too
* simple drivers can just add their own hooks and call it from this
* CRTC callback here by looping over all encoders connected to it using
* for_each_encoder_on_crtc().
*
* This hook is used only by atomic helpers. Atomic drivers don't
* need to implement it if there's no need to disable anything at the
* CRTC level.
*
* This function is optional.
*/
void (*atomic_disable)(struct drm_crtc *crtc,
struct drm_atomic_state *state);
/**
* @get_scanout_position:
*
* Called by vblank timestamping code.
*
* Returns the current display scanout position from a CRTC and an
* optional accurate ktime_get() timestamp of when the position was
* measured. Note that this is a helper callback which is only used
* if a driver uses drm_crtc_vblank_helper_get_vblank_timestamp()
* for the @drm_crtc_funcs.get_vblank_timestamp callback.
*
* Parameters:
*
* crtc:
* The CRTC.
* in_vblank_irq:
* True when called from drm_crtc_handle_vblank(). Some drivers
* need to apply some workarounds for gpu-specific vblank irq
* quirks if the flag is set.
* vpos:
* Target location for current vertical scanout position.
* hpos:
* Target location for current horizontal scanout position.
* stime:
* Target location for timestamp taken immediately before
* scanout position query. Can be NULL to skip timestamp.
* etime:
* Target location for timestamp taken immediately after
* scanout position query. Can be NULL to skip timestamp.
* mode:
* Current display timings.
*
* Returns vpos as a positive number while in active scanout area.
* Returns vpos as a negative number inside vblank, counting the number
* of scanlines to go until end of vblank, e.g., -1 means "one scanline
* until start of active scanout / end of vblank."
*
* Returns:
*
* True on success, false if a reliable scanout position counter could
* not be read out.
*/
bool (*get_scanout_position)(struct drm_crtc *crtc,
bool in_vblank_irq, int *vpos, int *hpos,
ktime_t *stime, ktime_t *etime,
const struct drm_display_mode *mode);
};
/**
* drm_crtc_helper_add - sets the helper vtable for a crtc
* @crtc: DRM CRTC
* @funcs: helper vtable to set for @crtc
*/
static inline void drm_crtc_helper_add(struct drm_crtc *crtc,
const struct drm_crtc_helper_funcs *funcs)
{
crtc->helper_private = funcs;
}
/**
* struct drm_encoder_helper_funcs - helper operations for encoders
*
* These hooks are used by the legacy CRTC helpers, the transitional plane
* helpers and the new atomic modesetting helpers.
*/
struct drm_encoder_helper_funcs {
/**
* @dpms:
*
* Callback to control power levels on the encoder. If the mode passed in
* is unsupported, the provider must use the next lowest power level.
* This is used by the legacy encoder helpers to implement DPMS
* functionality in drm_helper_connector_dpms().
*
* This callback is also used to disable an encoder by calling it with
* DRM_MODE_DPMS_OFF if the @disable hook isn't used.
*
* This callback is used by the legacy CRTC helpers. Atomic helpers
* also support using this hook for enabling and disabling an encoder to
* facilitate transitions to atomic, but it is deprecated. Instead
* @enable and @disable should be used.
*/
void (*dpms)(struct drm_encoder *encoder, int mode);
/**
* @mode_valid:
*
* This callback is used to check if a specific mode is valid in this
* encoder. This should be implemented if the encoder has some sort
* of restriction in the modes it can display. For example, a given
* encoder may be responsible to set a clock value. If the clock can
* not produce all the values for the available modes then this callback
* can be used to restrict the number of modes to only the ones that
* can be displayed.
*
* This hook is used by the probe helpers to filter the mode list in
* drm_helper_probe_single_connector_modes(), and it is used by the
* atomic helpers to validate modes supplied by userspace in
* drm_atomic_helper_check_modeset().
*
* This function is optional.
*
* NOTE:
*
* Since this function is both called from the check phase of an atomic
* commit, and the mode validation in the probe paths it is not allowed
* to look at anything else but the passed-in mode, and validate it
* against configuration-invariant hardward constraints. Any further
* limits which depend upon the configuration can only be checked in
* @mode_fixup or @atomic_check.
*
* RETURNS:
*
* drm_mode_status Enum
*/
enum drm_mode_status (*mode_valid)(struct drm_encoder *crtc,
const struct drm_display_mode *mode);
/**
* @mode_fixup:
*
* This callback is used to validate and adjust a mode. The parameter
* mode is the display mode that should be fed to the next element in
* the display chain, either the final &drm_connector or a &drm_bridge.
* The parameter adjusted_mode is the input mode the encoder requires. It
* can be modified by this callback and does not need to match mode. See
* also &drm_crtc_state.adjusted_mode for more details.
*
* This function is used by both legacy CRTC helpers and atomic helpers.
* This hook is optional.
*
* NOTE:
*
* This function is called in the check phase of atomic modesets, which
* can be aborted for any reason (including on userspace's request to
* just check whether a configuration would be possible). Atomic drivers
* MUST NOT touch any persistent state (hardware or software) or data
* structures except the passed in adjusted_mode parameter.
*
* This is in contrast to the legacy CRTC helpers where this was
* allowed.
*
* Atomic drivers which need to inspect and adjust more state should
* instead use the @atomic_check callback. If @atomic_check is used,
* this hook isn't called since @atomic_check allows a strict superset
* of the functionality of @mode_fixup.
*
* Also beware that userspace can request its own custom modes, neither
* core nor helpers filter modes to the list of probe modes reported by
* the GETCONNECTOR IOCTL and stored in &drm_connector.modes. To ensure
* that modes are filtered consistently put any encoder constraints and
* limits checks into @mode_valid.
*
* RETURNS:
*
* True if an acceptable configuration is possible, false if the modeset
* operation should be rejected.
*/
bool (*mode_fixup)(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
/**
* @prepare:
*
* This callback should prepare the encoder for a subsequent modeset,
* which in practice means the driver should disable the encoder if it
* is running. Most drivers ended up implementing this by calling their
* @dpms hook with DRM_MODE_DPMS_OFF.
*
* This callback is used by the legacy CRTC helpers. Atomic helpers
* also support using this hook for disabling an encoder to facilitate
* transitions to atomic, but it is deprecated. Instead @disable should
* be used.
*/
void (*prepare)(struct drm_encoder *encoder);
/**
* @commit:
*
* This callback should commit the new mode on the encoder after a modeset,
* which in practice means the driver should enable the encoder. Most
* drivers ended up implementing this by calling their @dpms hook with
* DRM_MODE_DPMS_ON.
*
* This callback is used by the legacy CRTC helpers. Atomic helpers
* also support using this hook for enabling an encoder to facilitate
* transitions to atomic, but it is deprecated. Instead @enable should
* be used.
*/
void (*commit)(struct drm_encoder *encoder);
/**
* @mode_set:
*
* This callback is used to update the display mode of an encoder.
*
* Note that the display pipe is completely off when this function is
* called. Drivers which need hardware to be running before they program
* the new display mode (because they implement runtime PM) should not
* use this hook, because the helper library calls it only once and not
* every time the display pipeline is suspend using either DPMS or the
* new "ACTIVE" property. Such drivers should instead move all their
* encoder setup into the @enable callback.
*
* This callback is used both by the legacy CRTC helpers and the atomic
* modeset helpers. It is optional in the atomic helpers.
*
* NOTE:
*
* If the driver uses the atomic modeset helpers and needs to inspect
* the connector state or connector display info during mode setting,
* @atomic_mode_set can be used instead.
*/
void (*mode_set)(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
/**
* @atomic_mode_set:
*
* This callback is used to update the display mode of an encoder.
*
* Note that the display pipe is completely off when this function is
* called. Drivers which need hardware to be running before they program
* the new display mode (because they implement runtime PM) should not
* use this hook, because the helper library calls it only once and not
* every time the display pipeline is suspended using either DPMS or the
* new "ACTIVE" property. Such drivers should instead move all their
* encoder setup into the @enable callback.
*
* This callback is used by the atomic modeset helpers in place of the
* @mode_set callback, if set by the driver. It is optional and should
* be used instead of @mode_set if the driver needs to inspect the
* connector state or display info, since there is no direct way to
* go from the encoder to the current connector.
*/
void (*atomic_mode_set)(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state);
/**
* @detect:
*
* This callback can be used by drivers who want to do detection on the
* encoder object instead of in connector functions.
*
* It is not used by any helper and therefore has purely driver-specific
* semantics. New drivers shouldn't use this and instead just implement
* their own private callbacks.
*
* FIXME:
*
* This should just be converted into a pile of driver vfuncs.
* Currently radeon, amdgpu and nouveau are using it.
*/
enum drm_connector_status (*detect)(struct drm_encoder *encoder,
struct drm_connector *connector);
/**
* @atomic_disable:
*
* This callback should be used to disable the encoder. With the atomic
* drivers it is called before this encoder's CRTC has been shut off
* using their own &drm_crtc_helper_funcs.atomic_disable hook. If that
* sequence is too simple drivers can just add their own driver private
* encoder hooks and call them from CRTC's callback by looping over all
* encoders connected to it using for_each_encoder_on_crtc().
*
* This callback is a variant of @disable that provides the atomic state
* to the driver. If @atomic_disable is implemented, @disable is not
* called by the helpers.
*
* This hook is only used by atomic helpers. Atomic drivers don't need
* to implement it if there's no need to disable anything at the encoder
* level. To ensure that runtime PM handling (using either DPMS or the
* new "ACTIVE" property) works @atomic_disable must be the inverse of
* @atomic_enable.
*/
void (*atomic_disable)(struct drm_encoder *encoder,
struct drm_atomic_state *state);
/**
* @atomic_enable:
*
* This callback should be used to enable the encoder. It is called
* after this encoder's CRTC has been enabled using their own
* &drm_crtc_helper_funcs.atomic_enable hook. If that sequence is
* too simple drivers can just add their own driver private encoder
* hooks and call them from CRTC's callback by looping over all encoders
* connected to it using for_each_encoder_on_crtc().
*
* This callback is a variant of @enable that provides the atomic state
* to the driver. If @atomic_enable is implemented, @enable is not
* called by the helpers.
*
* This hook is only used by atomic helpers, it is the opposite of
* @atomic_disable. Atomic drivers don't need to implement it if there's
* no need to enable anything at the encoder level. To ensure that
* runtime PM handling works @atomic_enable must be the inverse of
* @atomic_disable.
*/
void (*atomic_enable)(struct drm_encoder *encoder,
struct drm_atomic_state *state);
/**
* @disable:
*
* This callback should be used to disable the encoder. With the atomic
* drivers it is called before this encoder's CRTC has been shut off
* using their own &drm_crtc_helper_funcs.disable hook. If that
* sequence is too simple drivers can just add their own driver private
* encoder hooks and call them from CRTC's callback by looping over all
* encoders connected to it using for_each_encoder_on_crtc().
*
* This hook is used both by legacy CRTC helpers and atomic helpers.
* Atomic drivers don't need to implement it if there's no need to
* disable anything at the encoder level. To ensure that runtime PM
* handling (using either DPMS or the new "ACTIVE" property) works
* @disable must be the inverse of @enable for atomic drivers.
*
* For atomic drivers also consider @atomic_disable and save yourself
* from having to read the NOTE below!
*
* NOTE:
*
* With legacy CRTC helpers there's a big semantic difference between
* @disable and other hooks (like @prepare or @dpms) used to shut down a
* encoder: @disable is only called when also logically disabling the
* display pipeline and needs to release any resources acquired in
* @mode_set (like shared PLLs, or again release pinned framebuffers).
*
* Therefore @disable must be the inverse of @mode_set plus @commit for
* drivers still using legacy CRTC helpers, which is different from the
* rules under atomic.
*/
void (*disable)(struct drm_encoder *encoder);
/**
* @enable:
*
* This callback should be used to enable the encoder. With the atomic
* drivers it is called after this encoder's CRTC has been enabled using
* their own &drm_crtc_helper_funcs.enable hook. If that sequence is
* too simple drivers can just add their own driver private encoder
* hooks and call them from CRTC's callback by looping over all encoders
* connected to it using for_each_encoder_on_crtc().
*
* This hook is only used by atomic helpers, it is the opposite of
* @disable. Atomic drivers don't need to implement it if there's no
* need to enable anything at the encoder level. To ensure that
* runtime PM handling (using either DPMS or the new "ACTIVE" property)
* works @enable must be the inverse of @disable for atomic drivers.
*/
void (*enable)(struct drm_encoder *encoder);
/**
* @atomic_check:
*
* This callback is used to validate encoder state for atomic drivers.
* Since the encoder is the object connecting the CRTC and connector it
* gets passed both states, to be able to validate interactions and
* update the CRTC to match what the encoder needs for the requested
* connector.
*
* Since this provides a strict superset of the functionality of
* @mode_fixup (the requested and adjusted modes are both available
* through the passed in &struct drm_crtc_state) @mode_fixup is not
* called when @atomic_check is implemented.
*
* This function is used by the atomic helpers, but it is optional.
*
* NOTE:
*
* This function is called in the check phase of an atomic update. The
* driver is not allowed to change anything outside of the free-standing
* state objects passed-in or assembled in the overall &drm_atomic_state
* update tracking structure.
*
* Also beware that userspace can request its own custom modes, neither
* core nor helpers filter modes to the list of probe modes reported by
* the GETCONNECTOR IOCTL and stored in &drm_connector.modes. To ensure
* that modes are filtered consistently put any encoder constraints and
* limits checks into @mode_valid.
*
* RETURNS:
*
* 0 on success, -EINVAL if the state or the transition can't be
* supported, -ENOMEM on memory allocation failure and -EDEADLK if an
* attempt to obtain another state object ran into a &drm_modeset_lock
* deadlock.
*/
int (*atomic_check)(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state);
};
/**
* drm_encoder_helper_add - sets the helper vtable for an encoder
* @encoder: DRM encoder
* @funcs: helper vtable to set for @encoder
*/
static inline void drm_encoder_helper_add(struct drm_encoder *encoder,
const struct drm_encoder_helper_funcs *funcs)
{
encoder->helper_private = funcs;
}
/**
* struct drm_connector_helper_funcs - helper operations for connectors
*
* These functions are used by the atomic and legacy modeset helpers and by the
* probe helpers.
*/
struct drm_connector_helper_funcs {
/**
* @get_modes:
*
* This function should fill in all modes currently valid for the sink
* into the &drm_connector.probed_modes list. It should also update the
* EDID property by calling drm_connector_update_edid_property().
*
* The usual way to implement this is to cache the EDID retrieved in the
* probe callback somewhere in the driver-private connector structure.
* In this function drivers then parse the modes in the EDID and add
* them by calling drm_add_edid_modes(). But connectors that drive a
* fixed panel can also manually add specific modes using
* drm_mode_probed_add(). Drivers which manually add modes should also
* make sure that the &drm_connector.display_info,
* &drm_connector.width_mm and &drm_connector.height_mm fields are
* filled in.
*
* Note that the caller function will automatically add standard VESA
* DMT modes up to 1024x768 if the .get_modes() helper operation returns
* no mode and if the connector status is connector_status_connected or
* connector_status_unknown. There is no need to call
* drm_add_modes_noedid() manually in that case.
*
* Virtual drivers that just want some standard VESA mode with a given
* resolution can call drm_add_modes_noedid(), and mark the preferred
* one using drm_set_preferred_mode().
*
* This function is only called after the @detect hook has indicated
* that a sink is connected and when the EDID isn't overridden through
* sysfs or the kernel commandline.
*
* This callback is used by the probe helpers in e.g.
* drm_helper_probe_single_connector_modes().
*
* To avoid races with concurrent connector state updates, the helper
* libraries always call this with the &drm_mode_config.connection_mutex
* held. Because of this it's safe to inspect &drm_connector->state.
*
* RETURNS:
*
* The number of modes added by calling drm_mode_probed_add().
*/
int (*get_modes)(struct drm_connector *connector);
/**
* @detect_ctx:
*
* Check to see if anything is attached to the connector. The parameter
* force is set to false whilst polling, true when checking the
* connector due to a user request. force can be used by the driver to
* avoid expensive, destructive operations during automated probing.
*
* This callback is optional, if not implemented the connector will be
* considered as always being attached.
*
* This is the atomic version of &drm_connector_funcs.detect.
*
* To avoid races against concurrent connector state updates, the
* helper libraries always call this with ctx set to a valid context,
* and &drm_mode_config.connection_mutex will always be locked with
* the ctx parameter set to this ctx. This allows taking additional
* locks as required.
*
* RETURNS:
*
* &drm_connector_status indicating the connector's status,
* or the error code returned by drm_modeset_lock(), -EDEADLK.
*/
int (*detect_ctx)(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
bool force);
/**
* @mode_valid:
*
* Callback to validate a mode for a connector, irrespective of the
* specific display configuration.
*
* This callback is used by the probe helpers to filter the mode list
* (which is usually derived from the EDID data block from the sink).
* See e.g. drm_helper_probe_single_connector_modes().
*
* This function is optional.
*
* NOTE:
*
* This only filters the mode list supplied to userspace in the
* GETCONNECTOR IOCTL. Compared to &drm_encoder_helper_funcs.mode_valid,
* &drm_crtc_helper_funcs.mode_valid and &drm_bridge_funcs.mode_valid,
* which are also called by the atomic helpers from
* drm_atomic_helper_check_modeset(). This allows userspace to force and
* ignore sink constraint (like the pixel clock limits in the screen's
* EDID), which is useful for e.g. testing, or working around a broken
* EDID. Any source hardware constraint (which always need to be
* enforced) therefore should be checked in one of the above callbacks,
* and not this one here.
*
* To avoid races with concurrent connector state updates, the helper
* libraries always call this with the &drm_mode_config.connection_mutex
* held. Because of this it's safe to inspect &drm_connector->state.
*
* RETURNS:
*
* Either &drm_mode_status.MODE_OK or one of the failure reasons in &enum
* drm_mode_status.
*/
enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
struct drm_display_mode *mode);
/**
* @mode_valid_ctx:
*
* Callback to validate a mode for a connector, irrespective of the
* specific display configuration.
*
* This callback is used by the probe helpers to filter the mode list
* (which is usually derived from the EDID data block from the sink).
* See e.g. drm_helper_probe_single_connector_modes().
*
* This function is optional, and is the atomic version of
* &drm_connector_helper_funcs.mode_valid.
*
* To allow for accessing the atomic state of modesetting objects, the
* helper libraries always call this with ctx set to a valid context,
* and &drm_mode_config.connection_mutex will always be locked with
* the ctx parameter set to @ctx. This allows for taking additional
* locks as required.
*
* Even though additional locks may be acquired, this callback is
* still expected not to take any constraints into account which would
* be influenced by the currently set display state - such constraints
* should be handled in the driver's atomic check. For example, if a
* connector shares display bandwidth with other connectors then it
* would be ok to validate the minimum bandwidth requirement of a mode
* against the maximum possible bandwidth of the connector. But it
* wouldn't be ok to take the current bandwidth usage of other
* connectors into account, as this would change depending on the
* display state.
*
* Returns:
* 0 if &drm_connector_helper_funcs.mode_valid_ctx succeeded and wrote
* the &enum drm_mode_status value to @status, or a negative error