1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <drm/drm_connector.h>
24#include <drm/drm_edid.h>
25#include <drm/drm_encoder.h>
26#include <drm/drm_utils.h>
27#include <drm/drm_print.h>
28#include <drm/drm_drv.h>
29#include <drm/drm_file.h>
30#include <drm/drm_sysfs.h>
31
32#include <linux/uaccess.h>
33
34#include "drm_crtc_internal.h"
35#include "drm_internal.h"
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
67struct drm_conn_prop_enum_list {
68 int type;
69 const char *name;
70 struct ida ida;
71};
72
73
74
75
76static struct drm_conn_prop_enum_list drm_connector_enum_list[] = {
77 { DRM_MODE_CONNECTOR_Unknown, "Unknown" },
78 { DRM_MODE_CONNECTOR_VGA, "VGA" },
79 { DRM_MODE_CONNECTOR_DVII, "DVI-I" },
80 { DRM_MODE_CONNECTOR_DVID, "DVI-D" },
81 { DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
82 { DRM_MODE_CONNECTOR_Composite, "Composite" },
83 { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" },
84 { DRM_MODE_CONNECTOR_LVDS, "LVDS" },
85 { DRM_MODE_CONNECTOR_Component, "Component" },
86 { DRM_MODE_CONNECTOR_9PinDIN, "DIN" },
87 { DRM_MODE_CONNECTOR_DisplayPort, "DP" },
88 { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
89 { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
90 { DRM_MODE_CONNECTOR_TV, "TV" },
91 { DRM_MODE_CONNECTOR_eDP, "eDP" },
92 { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
93 { DRM_MODE_CONNECTOR_DSI, "DSI" },
94 { DRM_MODE_CONNECTOR_DPI, "DPI" },
95 { DRM_MODE_CONNECTOR_WRITEBACK, "Writeback" },
96 { DRM_MODE_CONNECTOR_SPI, "SPI" },
97};
98
99void drm_connector_ida_init(void)
100{
101 int i;
102
103 for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++)
104 ida_init(&drm_connector_enum_list[i].ida);
105}
106
107void drm_connector_ida_destroy(void)
108{
109 int i;
110
111 for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++)
112 ida_destroy(&drm_connector_enum_list[i].ida);
113}
114
115
116
117
118
119
120
121const char *drm_get_connector_type_name(unsigned int type)
122{
123 if (type < ARRAY_SIZE(drm_connector_enum_list))
124 return drm_connector_enum_list[type].name;
125
126 return NULL;
127}
128EXPORT_SYMBOL(drm_get_connector_type_name);
129
130
131
132
133
134
135
136
137
138
139
140static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
141{
142 struct drm_cmdline_mode *mode = &connector->cmdline_mode;
143 char *option = NULL;
144
145 if (fb_get_options(connector->name, &option))
146 return;
147
148 if (!drm_mode_parse_command_line_for_connector(option,
149 connector,
150 mode))
151 return;
152
153 if (mode->force) {
154 DRM_INFO("forcing %s connector %s\n", connector->name,
155 drm_get_connector_force_name(mode->force));
156 connector->force = mode->force;
157 }
158
159 if (mode->panel_orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN) {
160 DRM_INFO("cmdline forces connector %s panel_orientation to %d\n",
161 connector->name, mode->panel_orientation);
162 drm_connector_set_panel_orientation(connector,
163 mode->panel_orientation);
164 }
165
166 DRM_DEBUG_KMS("cmdline mode for connector %s %s %dx%d@%dHz%s%s%s\n",
167 connector->name, mode->name,
168 mode->xres, mode->yres,
169 mode->refresh_specified ? mode->refresh : 60,
170 mode->rb ? " reduced blanking" : "",
171 mode->margins ? " with margins" : "",
172 mode->interlace ? " interlaced" : "");
173}
174
175static void drm_connector_free(struct kref *kref)
176{
177 struct drm_connector *connector =
178 container_of(kref, struct drm_connector, base.refcount);
179 struct drm_device *dev = connector->dev;
180
181 drm_mode_object_unregister(dev, &connector->base);
182 connector->funcs->destroy(connector);
183}
184
185void drm_connector_free_work_fn(struct work_struct *work)
186{
187 struct drm_connector *connector, *n;
188 struct drm_device *dev =
189 container_of(work, struct drm_device, mode_config.connector_free_work);
190 struct drm_mode_config *config = &dev->mode_config;
191 unsigned long flags;
192 struct llist_node *freed;
193
194 spin_lock_irqsave(&config->connector_list_lock, flags);
195 freed = llist_del_all(&config->connector_free_list);
196 spin_unlock_irqrestore(&config->connector_list_lock, flags);
197
198 llist_for_each_entry_safe(connector, n, freed, free_node) {
199 drm_mode_object_unregister(dev, &connector->base);
200 connector->funcs->destroy(connector);
201 }
202}
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217int drm_connector_init(struct drm_device *dev,
218 struct drm_connector *connector,
219 const struct drm_connector_funcs *funcs,
220 int connector_type)
221{
222 struct drm_mode_config *config = &dev->mode_config;
223 int ret;
224 struct ida *connector_ida =
225 &drm_connector_enum_list[connector_type].ida;
226
227 WARN_ON(drm_drv_uses_atomic_modeset(dev) &&
228 (!funcs->atomic_destroy_state ||
229 !funcs->atomic_duplicate_state));
230
231 ret = __drm_mode_object_add(dev, &connector->base,
232 DRM_MODE_OBJECT_CONNECTOR,
233 false, drm_connector_free);
234 if (ret)
235 return ret;
236
237 connector->base.properties = &connector->properties;
238 connector->dev = dev;
239 connector->funcs = funcs;
240
241
242 ret = ida_simple_get(&config->connector_ida, 0, 32, GFP_KERNEL);
243 if (ret < 0) {
244 DRM_DEBUG_KMS("Failed to allocate %s connector index: %d\n",
245 drm_connector_enum_list[connector_type].name,
246 ret);
247 goto out_put;
248 }
249 connector->index = ret;
250 ret = 0;
251
252 connector->connector_type = connector_type;
253 connector->connector_type_id =
254 ida_simple_get(connector_ida, 1, 0, GFP_KERNEL);
255 if (connector->connector_type_id < 0) {
256 ret = connector->connector_type_id;
257 goto out_put_id;
258 }
259 connector->name =
260 kasprintf(GFP_KERNEL, "%s-%d",
261 drm_connector_enum_list[connector_type].name,
262 connector->connector_type_id);
263 if (!connector->name) {
264 ret = -ENOMEM;
265 goto out_put_type_id;
266 }
267
268 INIT_LIST_HEAD(&connector->probed_modes);
269 INIT_LIST_HEAD(&connector->modes);
270 mutex_init(&connector->mutex);
271 connector->edid_blob_ptr = NULL;
272 connector->epoch_counter = 0;
273 connector->tile_blob_ptr = NULL;
274 connector->status = connector_status_unknown;
275 connector->display_info.panel_orientation =
276 DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
277
278 drm_connector_get_cmdline_mode(connector);
279
280
281
282 spin_lock_irq(&config->connector_list_lock);
283 list_add_tail(&connector->head, &config->connector_list);
284 config->num_connector++;
285 spin_unlock_irq(&config->connector_list_lock);
286
287 if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL &&
288 connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
289 drm_connector_attach_edid_property(connector);
290
291 drm_object_attach_property(&connector->base,
292 config->dpms_property, 0);
293
294 drm_object_attach_property(&connector->base,
295 config->link_status_property,
296 0);
297
298 drm_object_attach_property(&connector->base,
299 config->non_desktop_property,
300 0);
301 drm_object_attach_property(&connector->base,
302 config->tile_property,
303 0);
304
305 if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
306 drm_object_attach_property(&connector->base, config->prop_crtc_id, 0);
307 }
308
309 connector->debugfs_entry = NULL;
310out_put_type_id:
311 if (ret)
312 ida_simple_remove(connector_ida, connector->connector_type_id);
313out_put_id:
314 if (ret)
315 ida_simple_remove(&config->connector_ida, connector->index);
316out_put:
317 if (ret)
318 drm_mode_object_unregister(dev, &connector->base);
319
320 return ret;
321}
322EXPORT_SYMBOL(drm_connector_init);
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340int drm_connector_init_with_ddc(struct drm_device *dev,
341 struct drm_connector *connector,
342 const struct drm_connector_funcs *funcs,
343 int connector_type,
344 struct i2c_adapter *ddc)
345{
346 int ret;
347
348 ret = drm_connector_init(dev, connector, funcs, connector_type);
349 if (ret)
350 return ret;
351
352
353 connector->ddc = ddc;
354
355 return ret;
356}
357EXPORT_SYMBOL(drm_connector_init_with_ddc);
358
359
360
361
362
363
364
365
366
367void drm_connector_attach_edid_property(struct drm_connector *connector)
368{
369 struct drm_mode_config *config = &connector->dev->mode_config;
370
371 drm_object_attach_property(&connector->base,
372 config->edid_property,
373 0);
374}
375EXPORT_SYMBOL(drm_connector_attach_edid_property);
376
377
378
379
380
381
382
383
384
385
386
387
388
389int drm_connector_attach_encoder(struct drm_connector *connector,
390 struct drm_encoder *encoder)
391{
392
393
394
395
396
397
398
399
400
401
402
403 if (WARN_ON(connector->encoder))
404 return -EINVAL;
405
406 connector->possible_encoders |= drm_encoder_mask(encoder);
407
408 return 0;
409}
410EXPORT_SYMBOL(drm_connector_attach_encoder);
411
412
413
414
415
416
417
418
419
420
421bool drm_connector_has_possible_encoder(struct drm_connector *connector,
422 struct drm_encoder *encoder)
423{
424 return connector->possible_encoders & drm_encoder_mask(encoder);
425}
426EXPORT_SYMBOL(drm_connector_has_possible_encoder);
427
428static void drm_mode_remove(struct drm_connector *connector,
429 struct drm_display_mode *mode)
430{
431 list_del(&mode->head);
432 drm_mode_destroy(connector->dev, mode);
433}
434
435
436
437
438
439
440
441void drm_connector_cleanup(struct drm_connector *connector)
442{
443 struct drm_device *dev = connector->dev;
444 struct drm_display_mode *mode, *t;
445
446
447
448
449 if (WARN_ON(connector->registration_state ==
450 DRM_CONNECTOR_REGISTERED))
451 drm_connector_unregister(connector);
452
453 if (connector->tile_group) {
454 drm_mode_put_tile_group(dev, connector->tile_group);
455 connector->tile_group = NULL;
456 }
457
458 list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
459 drm_mode_remove(connector, mode);
460
461 list_for_each_entry_safe(mode, t, &connector->modes, head)
462 drm_mode_remove(connector, mode);
463
464 ida_simple_remove(&drm_connector_enum_list[connector->connector_type].ida,
465 connector->connector_type_id);
466
467 ida_simple_remove(&dev->mode_config.connector_ida,
468 connector->index);
469
470 kfree(connector->display_info.bus_formats);
471 drm_mode_object_unregister(dev, &connector->base);
472 kfree(connector->name);
473 connector->name = NULL;
474 spin_lock_irq(&dev->mode_config.connector_list_lock);
475 list_del(&connector->head);
476 dev->mode_config.num_connector--;
477 spin_unlock_irq(&dev->mode_config.connector_list_lock);
478
479 WARN_ON(connector->state && !connector->funcs->atomic_destroy_state);
480 if (connector->state && connector->funcs->atomic_destroy_state)
481 connector->funcs->atomic_destroy_state(connector,
482 connector->state);
483
484 mutex_destroy(&connector->mutex);
485
486 memset(connector, 0, sizeof(*connector));
487}
488EXPORT_SYMBOL(drm_connector_cleanup);
489
490
491
492
493
494
495
496
497
498
499
500
501
502int drm_connector_register(struct drm_connector *connector)
503{
504 int ret = 0;
505
506 if (!connector->dev->registered)
507 return 0;
508
509 mutex_lock(&connector->mutex);
510 if (connector->registration_state != DRM_CONNECTOR_INITIALIZING)
511 goto unlock;
512
513 ret = drm_sysfs_connector_add(connector);
514 if (ret)
515 goto unlock;
516
517 drm_debugfs_connector_add(connector);
518
519 if (connector->funcs->late_register) {
520 ret = connector->funcs->late_register(connector);
521 if (ret)
522 goto err_debugfs;
523 }
524
525 drm_mode_object_register(connector->dev, &connector->base);
526
527 connector->registration_state = DRM_CONNECTOR_REGISTERED;
528
529
530 drm_sysfs_hotplug_event(connector->dev);
531
532 goto unlock;
533
534err_debugfs:
535 drm_debugfs_connector_remove(connector);
536 drm_sysfs_connector_remove(connector);
537unlock:
538 mutex_unlock(&connector->mutex);
539 return ret;
540}
541EXPORT_SYMBOL(drm_connector_register);
542
543
544
545
546
547
548
549
550
551
552void drm_connector_unregister(struct drm_connector *connector)
553{
554 mutex_lock(&connector->mutex);
555 if (connector->registration_state != DRM_CONNECTOR_REGISTERED) {
556 mutex_unlock(&connector->mutex);
557 return;
558 }
559
560 if (connector->funcs->early_unregister)
561 connector->funcs->early_unregister(connector);
562
563 drm_sysfs_connector_remove(connector);
564 drm_debugfs_connector_remove(connector);
565
566 connector->registration_state = DRM_CONNECTOR_UNREGISTERED;
567 mutex_unlock(&connector->mutex);
568}
569EXPORT_SYMBOL(drm_connector_unregister);
570
571void drm_connector_unregister_all(struct drm_device *dev)
572{
573 struct drm_connector *connector;
574 struct drm_connector_list_iter conn_iter;
575
576 drm_connector_list_iter_begin(dev, &conn_iter);
577 drm_for_each_connector_iter(connector, &conn_iter)
578 drm_connector_unregister(connector);
579 drm_connector_list_iter_end(&conn_iter);
580}
581
582int drm_connector_register_all(struct drm_device *dev)
583{
584 struct drm_connector *connector;
585 struct drm_connector_list_iter conn_iter;
586 int ret = 0;
587
588 drm_connector_list_iter_begin(dev, &conn_iter);
589 drm_for_each_connector_iter(connector, &conn_iter) {
590 ret = drm_connector_register(connector);
591 if (ret)
592 break;
593 }
594 drm_connector_list_iter_end(&conn_iter);
595
596 if (ret)
597 drm_connector_unregister_all(dev);
598 return ret;
599}
600
601
602
603
604
605
606
607
608const char *drm_get_connector_status_name(enum drm_connector_status status)
609{
610 if (status == connector_status_connected)
611 return "connected";
612 else if (status == connector_status_disconnected)
613 return "disconnected";
614 else
615 return "unknown";
616}
617EXPORT_SYMBOL(drm_get_connector_status_name);
618
619
620
621
622
623
624
625const char *drm_get_connector_force_name(enum drm_connector_force force)
626{
627 switch (force) {
628 case DRM_FORCE_UNSPECIFIED:
629 return "unspecified";
630 case DRM_FORCE_OFF:
631 return "off";
632 case DRM_FORCE_ON:
633 return "on";
634 case DRM_FORCE_ON_DIGITAL:
635 return "digital";
636 default:
637 return "unknown";
638 }
639}
640
641#ifdef CONFIG_LOCKDEP
642static struct lockdep_map connector_list_iter_dep_map = {
643 .name = "drm_connector_list_iter"
644};
645#endif
646
647
648
649
650
651
652
653
654
655
656
657void drm_connector_list_iter_begin(struct drm_device *dev,
658 struct drm_connector_list_iter *iter)
659{
660 iter->dev = dev;
661 iter->conn = NULL;
662 lock_acquire_shared_recursive(&connector_list_iter_dep_map, 0, 1, NULL, _RET_IP_);
663}
664EXPORT_SYMBOL(drm_connector_list_iter_begin);
665
666
667
668
669
670
671static void
672__drm_connector_put_safe(struct drm_connector *conn)
673{
674 struct drm_mode_config *config = &conn->dev->mode_config;
675
676 lockdep_assert_held(&config->connector_list_lock);
677
678 if (!refcount_dec_and_test(&conn->base.refcount.refcount))
679 return;
680
681 llist_add(&conn->free_node, &config->connector_free_list);
682 schedule_work(&config->connector_free_work);
683}
684
685
686
687
688
689
690
691
692struct drm_connector *
693drm_connector_list_iter_next(struct drm_connector_list_iter *iter)
694{
695 struct drm_connector *old_conn = iter->conn;
696 struct drm_mode_config *config = &iter->dev->mode_config;
697 struct list_head *lhead;
698 unsigned long flags;
699
700 spin_lock_irqsave(&config->connector_list_lock, flags);
701 lhead = old_conn ? &old_conn->head : &config->connector_list;
702
703 do {
704 if (lhead->next == &config->connector_list) {
705 iter->conn = NULL;
706 break;
707 }
708
709 lhead = lhead->next;
710 iter->conn = list_entry(lhead, struct drm_connector, head);
711
712
713 } while (!kref_get_unless_zero(&iter->conn->base.refcount));
714
715 if (old_conn)
716 __drm_connector_put_safe(old_conn);
717 spin_unlock_irqrestore(&config->connector_list_lock, flags);
718
719 return iter->conn;
720}
721EXPORT_SYMBOL(drm_connector_list_iter_next);
722
723
724
725
726
727
728
729
730
731
732void drm_connector_list_iter_end(struct drm_connector_list_iter *iter)
733{
734 struct drm_mode_config *config = &iter->dev->mode_config;
735 unsigned long flags;
736
737 iter->dev = NULL;
738 if (iter->conn) {
739 spin_lock_irqsave(&config->connector_list_lock, flags);
740 __drm_connector_put_safe(iter->conn);
741 spin_unlock_irqrestore(&config->connector_list_lock, flags);
742 }
743 lock_release(&connector_list_iter_dep_map, _RET_IP_);
744}
745EXPORT_SYMBOL(drm_connector_list_iter_end);
746
747static const struct drm_prop_enum_list drm_subpixel_enum_list[] = {
748 { SubPixelUnknown, "Unknown" },
749 { SubPixelHorizontalRGB, "Horizontal RGB" },
750 { SubPixelHorizontalBGR, "Horizontal BGR" },
751 { SubPixelVerticalRGB, "Vertical RGB" },
752 { SubPixelVerticalBGR, "Vertical BGR" },
753 { SubPixelNone, "None" },
754};
755
756
757
758
759
760
761
762
763const char *drm_get_subpixel_order_name(enum subpixel_order order)
764{
765 return drm_subpixel_enum_list[order].name;
766}
767EXPORT_SYMBOL(drm_get_subpixel_order_name);
768
769static const struct drm_prop_enum_list drm_dpms_enum_list[] = {
770 { DRM_MODE_DPMS_ON, "On" },
771 { DRM_MODE_DPMS_STANDBY, "Standby" },
772 { DRM_MODE_DPMS_SUSPEND, "Suspend" },
773 { DRM_MODE_DPMS_OFF, "Off" }
774};
775DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
776
777static const struct drm_prop_enum_list drm_link_status_enum_list[] = {
778 { DRM_MODE_LINK_STATUS_GOOD, "Good" },
779 { DRM_MODE_LINK_STATUS_BAD, "Bad" },
780};
781
782
783
784
785
786
787
788
789
790
791
792int drm_display_info_set_bus_formats(struct drm_display_info *info,
793 const u32 *formats,
794 unsigned int num_formats)
795{
796 u32 *fmts = NULL;
797
798 if (!formats && num_formats)
799 return -EINVAL;
800
801 if (formats && num_formats) {
802 fmts = kmemdup(formats, sizeof(*formats) * num_formats,
803 GFP_KERNEL);
804 if (!fmts)
805 return -ENOMEM;
806 }
807
808 kfree(info->bus_formats);
809 info->bus_formats = fmts;
810 info->num_bus_formats = num_formats;
811
812 return 0;
813}
814EXPORT_SYMBOL(drm_display_info_set_bus_formats);
815
816
817static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = {
818 { DRM_MODE_SCALE_NONE, "None" },
819 { DRM_MODE_SCALE_FULLSCREEN, "Full" },
820 { DRM_MODE_SCALE_CENTER, "Center" },
821 { DRM_MODE_SCALE_ASPECT, "Full aspect" },
822};
823
824static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = {
825 { DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" },
826 { DRM_MODE_PICTURE_ASPECT_4_3, "4:3" },
827 { DRM_MODE_PICTURE_ASPECT_16_9, "16:9" },
828};
829
830static const struct drm_prop_enum_list drm_content_type_enum_list[] = {
831 { DRM_MODE_CONTENT_TYPE_NO_DATA, "No Data" },
832 { DRM_MODE_CONTENT_TYPE_GRAPHICS, "Graphics" },
833 { DRM_MODE_CONTENT_TYPE_PHOTO, "Photo" },
834 { DRM_MODE_CONTENT_TYPE_CINEMA, "Cinema" },
835 { DRM_MODE_CONTENT_TYPE_GAME, "Game" },
836};
837
838static const struct drm_prop_enum_list drm_panel_orientation_enum_list[] = {
839 { DRM_MODE_PANEL_ORIENTATION_NORMAL, "Normal" },
840 { DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP, "Upside Down" },
841 { DRM_MODE_PANEL_ORIENTATION_LEFT_UP, "Left Side Up" },
842 { DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, "Right Side Up" },
843};
844
845static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = {
846 { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" },
847 { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" },
848 { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" },
849};
850DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list)
851
852static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = {
853 { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" },
854 { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" },
855 { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" },
856};
857DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name,
858 drm_dvi_i_subconnector_enum_list)
859
860static const struct drm_prop_enum_list drm_tv_select_enum_list[] = {
861 { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" },
862 { DRM_MODE_SUBCONNECTOR_Composite, "Composite" },
863 { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" },
864 { DRM_MODE_SUBCONNECTOR_Component, "Component" },
865 { DRM_MODE_SUBCONNECTOR_SCART, "SCART" },
866};
867DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list)
868
869static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = {
870 { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" },
871 { DRM_MODE_SUBCONNECTOR_Composite, "Composite" },
872 { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" },
873 { DRM_MODE_SUBCONNECTOR_Component, "Component" },
874 { DRM_MODE_SUBCONNECTOR_SCART, "SCART" },
875};
876DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
877 drm_tv_subconnector_enum_list)
878
879static const struct drm_prop_enum_list drm_dp_subconnector_enum_list[] = {
880 { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" },
881 { DRM_MODE_SUBCONNECTOR_VGA, "VGA" },
882 { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" },
883 { DRM_MODE_SUBCONNECTOR_HDMIA, "HDMI" },
884 { DRM_MODE_SUBCONNECTOR_DisplayPort, "DP" },
885 { DRM_MODE_SUBCONNECTOR_Wireless, "Wireless" },
886 { DRM_MODE_SUBCONNECTOR_Native, "Native" },
887};
888
889DRM_ENUM_NAME_FN(drm_get_dp_subconnector_name,
890 drm_dp_subconnector_enum_list)
891
892static const struct drm_prop_enum_list hdmi_colorspaces[] = {
893
894 { DRM_MODE_COLORIMETRY_DEFAULT, "Default" },
895
896 { DRM_MODE_COLORIMETRY_SMPTE_170M_YCC, "SMPTE_170M_YCC" },
897 { DRM_MODE_COLORIMETRY_BT709_YCC, "BT709_YCC" },
898
899 { DRM_MODE_COLORIMETRY_XVYCC_601, "XVYCC_601" },
900
901 { DRM_MODE_COLORIMETRY_XVYCC_709, "XVYCC_709" },
902
903 { DRM_MODE_COLORIMETRY_SYCC_601, "SYCC_601" },
904
905 { DRM_MODE_COLORIMETRY_OPYCC_601, "opYCC_601" },
906
907 { DRM_MODE_COLORIMETRY_OPRGB, "opRGB" },
908
909 { DRM_MODE_COLORIMETRY_BT2020_CYCC, "BT2020_CYCC" },
910
911 { DRM_MODE_COLORIMETRY_BT2020_RGB, "BT2020_RGB" },
912
913 { DRM_MODE_COLORIMETRY_BT2020_YCC, "BT2020_YCC" },
914
915 { DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65, "DCI-P3_RGB_D65" },
916 { DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER, "DCI-P3_RGB_Theater" },
917};
918
919
920
921
922
923static const struct drm_prop_enum_list dp_colorspaces[] = {
924
925 { DRM_MODE_COLORIMETRY_DEFAULT, "Default" },
926 { DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED, "RGB_Wide_Gamut_Fixed_Point" },
927
928 { DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT, "RGB_Wide_Gamut_Floating_Point" },
929
930 { DRM_MODE_COLORIMETRY_OPRGB, "opRGB" },
931
932 { DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65, "DCI-P3_RGB_D65" },
933
934 { DRM_MODE_COLORIMETRY_BT2020_RGB, "BT2020_RGB" },
935 { DRM_MODE_COLORIMETRY_BT601_YCC, "BT601_YCC" },
936 { DRM_MODE_COLORIMETRY_BT709_YCC, "BT709_YCC" },
937
938 { DRM_MODE_COLORIMETRY_XVYCC_601, "XVYCC_601" },
939
940 { DRM_MODE_COLORIMETRY_XVYCC_709, "XVYCC_709" },
941
942 { DRM_MODE_COLORIMETRY_SYCC_601, "SYCC_601" },
943
944 { DRM_MODE_COLORIMETRY_OPYCC_601, "opYCC_601" },
945
946 { DRM_MODE_COLORIMETRY_BT2020_CYCC, "BT2020_CYCC" },
947
948 { DRM_MODE_COLORIMETRY_BT2020_YCC, "BT2020_YCC" },
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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251int drm_connector_create_standard_properties(struct drm_device *dev)
1252{
1253 struct drm_property *prop;
1254
1255 prop = drm_property_create(dev, DRM_MODE_PROP_BLOB |
1256 DRM_MODE_PROP_IMMUTABLE,
1257 "EDID", 0);
1258 if (!prop)
1259 return -ENOMEM;
1260 dev->mode_config.edid_property = prop;
1261
1262 prop = drm_property_create_enum(dev, 0,
1263 "DPMS", drm_dpms_enum_list,
1264 ARRAY_SIZE(drm_dpms_enum_list));
1265 if (!prop)
1266 return -ENOMEM;
1267 dev->mode_config.dpms_property = prop;
1268
1269 prop = drm_property_create(dev,
1270 DRM_MODE_PROP_BLOB |
1271 DRM_MODE_PROP_IMMUTABLE,
1272 "PATH", 0);
1273 if (!prop)
1274 return -ENOMEM;
1275 dev->mode_config.path_property = prop;
1276
1277 prop = drm_property_create(dev,
1278 DRM_MODE_PROP_BLOB |
1279 DRM_MODE_PROP_IMMUTABLE,
1280 "TILE", 0);
1281 if (!prop)
1282 return -ENOMEM;
1283 dev->mode_config.tile_property = prop;
1284
1285 prop = drm_property_create_enum(dev, 0, "link-status",
1286 drm_link_status_enum_list,
1287 ARRAY_SIZE(drm_link_status_enum_list));
1288 if (!prop)
1289 return -ENOMEM;
1290 dev->mode_config.link_status_property = prop;
1291
1292 prop = drm_property_create_bool(dev, DRM_MODE_PROP_IMMUTABLE, "non-desktop");
1293 if (!prop)
1294 return -ENOMEM;
1295 dev->mode_config.non_desktop_property = prop;
1296
1297 prop = drm_property_create(dev, DRM_MODE_PROP_BLOB,
1298 "HDR_OUTPUT_METADATA", 0);
1299 if (!prop)
1300 return -ENOMEM;
1301 dev->mode_config.hdr_output_metadata_property = prop;
1302
1303 prop = drm_property_create(dev, DRM_MODE_PROP_BLOB,
1304 "GEN_HDR_OUTPUT_METADATA", 0);
1305 if (!prop)
1306 return -ENOMEM;
1307 dev->mode_config.gen_hdr_output_metadata_property = prop;
1308
1309 return 0;
1310}
1311
1312
1313
1314
1315
1316
1317
1318int drm_mode_create_dvi_i_properties(struct drm_device *dev)
1319{
1320 struct drm_property *dvi_i_selector;
1321 struct drm_property *dvi_i_subconnector;
1322
1323 if (dev->mode_config.dvi_i_select_subconnector_property)
1324 return 0;
1325
1326 dvi_i_selector =
1327 drm_property_create_enum(dev, 0,
1328 "select subconnector",
1329 drm_dvi_i_select_enum_list,
1330 ARRAY_SIZE(drm_dvi_i_select_enum_list));
1331 dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector;
1332
1333 dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
1334 "subconnector",
1335 drm_dvi_i_subconnector_enum_list,
1336 ARRAY_SIZE(drm_dvi_i_subconnector_enum_list));
1337 dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector;
1338
1339 return 0;
1340}
1341EXPORT_SYMBOL(drm_mode_create_dvi_i_properties);
1342
1343
1344
1345
1346
1347
1348
1349void drm_connector_attach_dp_subconnector_property(struct drm_connector *connector)
1350{
1351 struct drm_mode_config *mode_config = &connector->dev->mode_config;
1352
1353 if (!mode_config->dp_subconnector_property)
1354 mode_config->dp_subconnector_property =
1355 drm_property_create_enum(connector->dev,
1356 DRM_MODE_PROP_IMMUTABLE,
1357 "subconnector",
1358 drm_dp_subconnector_enum_list,
1359 ARRAY_SIZE(drm_dp_subconnector_enum_list));
1360
1361 drm_object_attach_property(&connector->base,
1362 mode_config->dp_subconnector_property,
1363 DRM_MODE_SUBCONNECTOR_Unknown);
1364}
1365EXPORT_SYMBOL(drm_connector_attach_dp_subconnector_property);
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399int drm_connector_attach_content_type_property(struct drm_connector *connector)
1400{
1401 if (!drm_mode_create_content_type_property(connector->dev))
1402 drm_object_attach_property(&connector->base,
1403 connector->dev->mode_config.content_type_property,
1404 DRM_MODE_CONTENT_TYPE_NO_DATA);
1405 return 0;
1406}
1407EXPORT_SYMBOL(drm_connector_attach_content_type_property);
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418void drm_hdmi_avi_infoframe_content_type(struct hdmi_avi_infoframe *frame,
1419 const struct drm_connector_state *conn_state)
1420{
1421 switch (conn_state->content_type) {
1422 case DRM_MODE_CONTENT_TYPE_GRAPHICS:
1423 frame->content_type = HDMI_CONTENT_TYPE_GRAPHICS;
1424 break;
1425 case DRM_MODE_CONTENT_TYPE_CINEMA:
1426 frame->content_type = HDMI_CONTENT_TYPE_CINEMA;
1427 break;
1428 case DRM_MODE_CONTENT_TYPE_GAME:
1429 frame->content_type = HDMI_CONTENT_TYPE_GAME;
1430 break;
1431 case DRM_MODE_CONTENT_TYPE_PHOTO:
1432 frame->content_type = HDMI_CONTENT_TYPE_PHOTO;
1433 break;
1434 default:
1435
1436 frame->content_type = HDMI_CONTENT_TYPE_GRAPHICS;
1437 }
1438
1439 frame->itc = conn_state->content_type != DRM_MODE_CONTENT_TYPE_NO_DATA;
1440}
1441EXPORT_SYMBOL(drm_hdmi_avi_infoframe_content_type);
1442
1443
1444
1445
1446
1447
1448
1449
1450void drm_connector_attach_tv_margin_properties(struct drm_connector *connector)
1451{
1452 struct drm_device *dev = connector->dev;
1453
1454 drm_object_attach_property(&connector->base,
1455 dev->mode_config.tv_left_margin_property,
1456 0);
1457 drm_object_attach_property(&connector->base,
1458 dev->mode_config.tv_right_margin_property,
1459 0);
1460 drm_object_attach_property(&connector->base,
1461 dev->mode_config.tv_top_margin_property,
1462 0);
1463 drm_object_attach_property(&connector->base,
1464 dev->mode_config.tv_bottom_margin_property,
1465 0);
1466}
1467EXPORT_SYMBOL(drm_connector_attach_tv_margin_properties);
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478int drm_mode_create_tv_margin_properties(struct drm_device *dev)
1479{
1480 if (dev->mode_config.tv_left_margin_property)
1481 return 0;
1482
1483 dev->mode_config.tv_left_margin_property =
1484 drm_property_create_range(dev, 0, "left margin", 0, 100);
1485 if (!dev->mode_config.tv_left_margin_property)
1486 return -ENOMEM;
1487
1488 dev->mode_config.tv_right_margin_property =
1489 drm_property_create_range(dev, 0, "right margin", 0, 100);
1490 if (!dev->mode_config.tv_right_margin_property)
1491 return -ENOMEM;
1492
1493 dev->mode_config.tv_top_margin_property =
1494 drm_property_create_range(dev, 0, "top margin", 0, 100);
1495 if (!dev->mode_config.tv_top_margin_property)
1496 return -ENOMEM;
1497
1498 dev->mode_config.tv_bottom_margin_property =
1499 drm_property_create_range(dev, 0, "bottom margin", 0, 100);
1500 if (!dev->mode_config.tv_bottom_margin_property)
1501 return -ENOMEM;
1502
1503 return 0;
1504}
1505EXPORT_SYMBOL(drm_mode_create_tv_margin_properties);
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518int drm_mode_create_tv_properties(struct drm_device *dev,
1519 unsigned int num_modes,
1520 const char * const modes[])
1521{
1522 struct drm_property *tv_selector;
1523 struct drm_property *tv_subconnector;
1524 unsigned int i;
1525
1526 if (dev->mode_config.tv_select_subconnector_property)
1527 return 0;
1528
1529
1530
1531
1532 tv_selector = drm_property_create_enum(dev, 0,
1533 "select subconnector",
1534 drm_tv_select_enum_list,
1535 ARRAY_SIZE(drm_tv_select_enum_list));
1536 if (!tv_selector)
1537 goto nomem;
1538
1539 dev->mode_config.tv_select_subconnector_property = tv_selector;
1540
1541 tv_subconnector =
1542 drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
1543 "subconnector",
1544 drm_tv_subconnector_enum_list,
1545 ARRAY_SIZE(drm_tv_subconnector_enum_list));
1546 if (!tv_subconnector)
1547 goto nomem;
1548 dev->mode_config.tv_subconnector_property = tv_subconnector;
1549
1550
1551
1552
1553 if (drm_mode_create_tv_margin_properties(dev))
1554 goto nomem;
1555
1556 dev->mode_config.tv_mode_property =
1557 drm_property_create(dev, DRM_MODE_PROP_ENUM,
1558 "mode", num_modes);
1559 if (!dev->mode_config.tv_mode_property)
1560 goto nomem;
1561
1562 for (i = 0; i < num_modes; i++)
1563 drm_property_add_enum(dev->mode_config.tv_mode_property,
1564 i, modes[i]);
1565
1566 dev->mode_config.tv_brightness_property =
1567 drm_property_create_range(dev, 0, "brightness", 0, 100);
1568 if (!dev->mode_config.tv_brightness_property)
1569 goto nomem;
1570
1571 dev->mode_config.tv_contrast_property =
1572 drm_property_create_range(dev, 0, "contrast", 0, 100);
1573 if (!dev->mode_config.tv_contrast_property)
1574 goto nomem;
1575
1576 dev->mode_config.tv_flicker_reduction_property =
1577 drm_property_create_range(dev, 0, "flicker reduction", 0, 100);
1578 if (!dev->mode_config.tv_flicker_reduction_property)
1579 goto nomem;
1580
1581 dev->mode_config.tv_overscan_property =
1582 drm_property_create_range(dev, 0, "overscan", 0, 100);
1583 if (!dev->mode_config.tv_overscan_property)
1584 goto nomem;
1585
1586 dev->mode_config.tv_saturation_property =
1587 drm_property_create_range(dev, 0, "saturation", 0, 100);
1588 if (!dev->mode_config.tv_saturation_property)
1589 goto nomem;
1590
1591 dev->mode_config.tv_hue_property =
1592 drm_property_create_range(dev, 0, "hue", 0, 100);
1593 if (!dev->mode_config.tv_hue_property)
1594 goto nomem;
1595
1596 return 0;
1597nomem:
1598 return -ENOMEM;
1599}
1600EXPORT_SYMBOL(drm_mode_create_tv_properties);
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613int drm_mode_create_scaling_mode_property(struct drm_device *dev)
1614{
1615 struct drm_property *scaling_mode;
1616
1617 if (dev->mode_config.scaling_mode_property)
1618 return 0;
1619
1620 scaling_mode =
1621 drm_property_create_enum(dev, 0, "scaling mode",
1622 drm_scaling_mode_enum_list,
1623 ARRAY_SIZE(drm_scaling_mode_enum_list));
1624
1625 dev->mode_config.scaling_mode_property = scaling_mode;
1626
1627 return 0;
1628}
1629EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704int drm_connector_attach_vrr_capable_property(
1705 struct drm_connector *connector)
1706{
1707 struct drm_device *dev = connector->dev;
1708 struct drm_property *prop;
1709
1710 if (!connector->vrr_capable_property) {
1711 prop = drm_property_create_bool(dev, DRM_MODE_PROP_IMMUTABLE,
1712 "vrr_capable");
1713 if (!prop)
1714 return -ENOMEM;
1715
1716 connector->vrr_capable_property = prop;
1717 drm_object_attach_property(&connector->base, prop, 0);
1718 }
1719
1720 return 0;
1721}
1722EXPORT_SYMBOL(drm_connector_attach_vrr_capable_property);
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738int drm_connector_attach_scaling_mode_property(struct drm_connector *connector,
1739 u32 scaling_mode_mask)
1740{
1741 struct drm_device *dev = connector->dev;
1742 struct drm_property *scaling_mode_property;
1743 int i;
1744 const unsigned valid_scaling_mode_mask =
1745 (1U << ARRAY_SIZE(drm_scaling_mode_enum_list)) - 1;
1746
1747 if (WARN_ON(hweight32(scaling_mode_mask) < 2 ||
1748 scaling_mode_mask & ~valid_scaling_mode_mask))
1749 return -EINVAL;
1750
1751 scaling_mode_property =
1752 drm_property_create(dev, DRM_MODE_PROP_ENUM, "scaling mode",
1753 hweight32(scaling_mode_mask));
1754
1755 if (!scaling_mode_property)
1756 return -ENOMEM;
1757
1758 for (i = 0; i < ARRAY_SIZE(drm_scaling_mode_enum_list); i++) {
1759 int ret;
1760
1761 if (!(BIT(i) & scaling_mode_mask))
1762 continue;
1763
1764 ret = drm_property_add_enum(scaling_mode_property,
1765 drm_scaling_mode_enum_list[i].type,
1766 drm_scaling_mode_enum_list[i].name);
1767
1768 if (ret) {
1769 drm_property_destroy(dev, scaling_mode_property);
1770
1771 return ret;
1772 }
1773 }
1774
1775 drm_object_attach_property(&connector->base,
1776 scaling_mode_property, 0);
1777
1778 connector->scaling_mode_property = scaling_mode_property;
1779
1780 return 0;
1781}
1782EXPORT_SYMBOL(drm_connector_attach_scaling_mode_property);
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794int drm_mode_create_aspect_ratio_property(struct drm_device *dev)
1795{
1796 if (dev->mode_config.aspect_ratio_property)
1797 return 0;
1798
1799 dev->mode_config.aspect_ratio_property =
1800 drm_property_create_enum(dev, 0, "aspect ratio",
1801 drm_aspect_ratio_enum_list,
1802 ARRAY_SIZE(drm_aspect_ratio_enum_list));
1803
1804 if (dev->mode_config.aspect_ratio_property == NULL)
1805 return -ENOMEM;
1806
1807 return 0;
1808}
1809EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property);
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849int drm_mode_create_hdmi_colorspace_property(struct drm_connector *connector)
1850{
1851 struct drm_device *dev = connector->dev;
1852
1853 if (connector->colorspace_property)
1854 return 0;
1855
1856 connector->colorspace_property =
1857 drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "Colorspace",
1858 hdmi_colorspaces,
1859 ARRAY_SIZE(hdmi_colorspaces));
1860
1861 if (!connector->colorspace_property)
1862 return -ENOMEM;
1863
1864 return 0;
1865}
1866EXPORT_SYMBOL(drm_mode_create_hdmi_colorspace_property);
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878int drm_mode_create_dp_colorspace_property(struct drm_connector *connector)
1879{
1880 struct drm_device *dev = connector->dev;
1881
1882 if (connector->colorspace_property)
1883 return 0;
1884
1885 connector->colorspace_property =
1886 drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "Colorspace",
1887 dp_colorspaces,
1888 ARRAY_SIZE(dp_colorspaces));
1889
1890 if (!connector->colorspace_property)
1891 return -ENOMEM;
1892
1893 return 0;
1894}
1895EXPORT_SYMBOL(drm_mode_create_dp_colorspace_property);
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907int drm_mode_create_content_type_property(struct drm_device *dev)
1908{
1909 if (dev->mode_config.content_type_property)
1910 return 0;
1911
1912 dev->mode_config.content_type_property =
1913 drm_property_create_enum(dev, 0, "content type",
1914 drm_content_type_enum_list,
1915 ARRAY_SIZE(drm_content_type_enum_list));
1916
1917 if (dev->mode_config.content_type_property == NULL)
1918 return -ENOMEM;
1919
1920 return 0;
1921}
1922EXPORT_SYMBOL(drm_mode_create_content_type_property);
1923
1924
1925
1926
1927
1928
1929
1930int drm_mode_create_suggested_offset_properties(struct drm_device *dev)
1931{
1932 if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property)
1933 return 0;
1934
1935 dev->mode_config.suggested_x_property =
1936 drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff);
1937
1938 dev->mode_config.suggested_y_property =
1939 drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff);
1940
1941 if (dev->mode_config.suggested_x_property == NULL ||
1942 dev->mode_config.suggested_y_property == NULL)
1943 return -ENOMEM;
1944 return 0;
1945}
1946EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties);
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961int drm_connector_set_path_property(struct drm_connector *connector,
1962 const char *path)
1963{
1964 struct drm_device *dev = connector->dev;
1965 int ret;
1966
1967 ret = drm_property_replace_global_blob(dev,
1968 &connector->path_blob_ptr,
1969 strlen(path) + 1,
1970 path,
1971 &connector->base,
1972 dev->mode_config.path_property);
1973 return ret;
1974}
1975EXPORT_SYMBOL(drm_connector_set_path_property);
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990int drm_connector_set_tile_property(struct drm_connector *connector)
1991{
1992 struct drm_device *dev = connector->dev;
1993 char tile[256];
1994 int ret;
1995
1996 if (!connector->has_tile) {
1997 ret = drm_property_replace_global_blob(dev,
1998 &connector->tile_blob_ptr,
1999 0,
2000 NULL,
2001 &connector->base,
2002 dev->mode_config.tile_property);
2003 return ret;
2004 }
2005
2006 snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d",
2007 connector->tile_group->id, connector->tile_is_single_monitor,
2008 connector->num_h_tile, connector->num_v_tile,
2009 connector->tile_h_loc, connector->tile_v_loc,
2010 connector->tile_h_size, connector->tile_v_size);
2011
2012 ret = drm_property_replace_global_blob(dev,
2013 &connector->tile_blob_ptr,
2014 strlen(tile) + 1,
2015 tile,
2016 &connector->base,
2017 dev->mode_config.tile_property);
2018 return ret;
2019}
2020EXPORT_SYMBOL(drm_connector_set_tile_property);
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036int drm_connector_update_edid_property(struct drm_connector *connector,
2037 const struct edid *edid)
2038{
2039 struct drm_device *dev = connector->dev;
2040 size_t size = 0;
2041 int ret;
2042 const struct edid *old_edid;
2043
2044
2045 if (connector->override_edid)
2046 return 0;
2047
2048 if (edid)
2049 size = EDID_LENGTH * (1 + edid->extensions);
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059 if (edid)
2060 drm_add_display_info(connector, edid);
2061 else
2062 drm_reset_display_info(connector);
2063
2064 drm_update_tile_info(connector, edid);
2065
2066 if (connector->edid_blob_ptr) {
2067 old_edid = (const struct edid *)connector->edid_blob_ptr->data;
2068 if (old_edid) {
2069 if (!drm_edid_are_equal(edid, old_edid)) {
2070 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Edid was changed.\n",
2071 connector->base.id, connector->name);
2072
2073 connector->epoch_counter += 1;
2074 DRM_DEBUG_KMS("Updating change counter to %llu\n",
2075 connector->epoch_counter);
2076 }
2077 }
2078 }
2079
2080 drm_object_property_set_value(&connector->base,
2081 dev->mode_config.non_desktop_property,
2082 connector->display_info.non_desktop);
2083
2084 ret = drm_property_replace_global_blob(dev,
2085 &connector->edid_blob_ptr,
2086 size,
2087 edid,
2088 &connector->base,
2089 dev->mode_config.edid_property);
2090 if (ret)
2091 return ret;
2092 return drm_connector_set_tile_property(connector);
2093}
2094EXPORT_SYMBOL(drm_connector_update_edid_property);
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115void drm_connector_set_link_status_property(struct drm_connector *connector,
2116 uint64_t link_status)
2117{
2118 struct drm_device *dev = connector->dev;
2119
2120 drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
2121 connector->state->link_status = link_status;
2122 drm_modeset_unlock(&dev->mode_config.connection_mutex);
2123}
2124EXPORT_SYMBOL(drm_connector_set_link_status_property);
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137int drm_connector_attach_max_bpc_property(struct drm_connector *connector,
2138 int min, int max)
2139{
2140 struct drm_device *dev = connector->dev;
2141 struct drm_property *prop;
2142
2143 prop = connector->max_bpc_property;
2144 if (!prop) {
2145 prop = drm_property_create_range(dev, 0, "max bpc", min, max);
2146 if (!prop)
2147 return -ENOMEM;
2148
2149 connector->max_bpc_property = prop;
2150 }
2151
2152 drm_object_attach_property(&connector->base, prop, max);
2153 connector->state->max_requested_bpc = max;
2154 connector->state->max_bpc = max;
2155
2156 return 0;
2157}
2158EXPORT_SYMBOL(drm_connector_attach_max_bpc_property);
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169void drm_connector_set_vrr_capable_property(
2170 struct drm_connector *connector, bool capable)
2171{
2172 drm_object_property_set_value(&connector->base,
2173 connector->vrr_capable_property,
2174 capable);
2175}
2176EXPORT_SYMBOL(drm_connector_set_vrr_capable_property);
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196int drm_connector_set_panel_orientation(
2197 struct drm_connector *connector,
2198 enum drm_panel_orientation panel_orientation)
2199{
2200 struct drm_device *dev = connector->dev;
2201 struct drm_display_info *info = &connector->display_info;
2202 struct drm_property *prop;
2203
2204
2205 if (info->panel_orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
2206 return 0;
2207
2208
2209 if (panel_orientation == DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
2210 return 0;
2211
2212 info->panel_orientation = panel_orientation;
2213
2214 prop = dev->mode_config.panel_orientation_property;
2215 if (!prop) {
2216 prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
2217 "panel orientation",
2218 drm_panel_orientation_enum_list,
2219 ARRAY_SIZE(drm_panel_orientation_enum_list));
2220 if (!prop)
2221 return -ENOMEM;
2222
2223 dev->mode_config.panel_orientation_property = prop;
2224 }
2225
2226 drm_object_attach_property(&connector->base, prop,
2227 info->panel_orientation);
2228 return 0;
2229}
2230EXPORT_SYMBOL(drm_connector_set_panel_orientation);
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246int drm_connector_set_panel_orientation_with_quirk(
2247 struct drm_connector *connector,
2248 enum drm_panel_orientation panel_orientation,
2249 int width, int height)
2250{
2251 int orientation_quirk;
2252
2253 orientation_quirk = drm_get_panel_orientation_quirk(width, height);
2254 if (orientation_quirk != DRM_MODE_PANEL_ORIENTATION_UNKNOWN)
2255 panel_orientation = orientation_quirk;
2256
2257 return drm_connector_set_panel_orientation(connector,
2258 panel_orientation);
2259}
2260EXPORT_SYMBOL(drm_connector_set_panel_orientation_with_quirk);
2261
2262int drm_connector_set_obj_prop(struct drm_mode_object *obj,
2263 struct drm_property *property,
2264 uint64_t value)
2265{
2266 int ret = -EINVAL;
2267 struct drm_connector *connector = obj_to_connector(obj);
2268
2269
2270 if (property == connector->dev->mode_config.dpms_property) {
2271 ret = (*connector->funcs->dpms)(connector, (int)value);
2272 } else if (connector->funcs->set_property)
2273 ret = connector->funcs->set_property(connector, property, value);
2274
2275 if (!ret)
2276 drm_object_property_set_value(&connector->base, property, value);
2277 return ret;
2278}
2279
2280int drm_connector_property_set_ioctl(struct drm_device *dev,
2281 void *data, struct drm_file *file_priv)
2282{
2283 struct drm_mode_connector_set_property *conn_set_prop = data;
2284 struct drm_mode_obj_set_property obj_set_prop = {
2285 .value = conn_set_prop->value,
2286 .prop_id = conn_set_prop->prop_id,
2287 .obj_id = conn_set_prop->connector_id,
2288 .obj_type = DRM_MODE_OBJECT_CONNECTOR
2289 };
2290
2291
2292 return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv);
2293}
2294
2295static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector)
2296{
2297
2298
2299 if (connector->state)
2300 return connector->state->best_encoder;
2301 return connector->encoder;
2302}
2303
2304static bool
2305drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
2306 const struct list_head *modes,
2307 const struct drm_file *file_priv)
2308{
2309
2310
2311
2312
2313 if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode))
2314 return false;
2315
2316
2317
2318
2319
2320
2321 if (!file_priv->aspect_ratio_allowed) {
2322 const struct drm_display_mode *mode_itr;
2323
2324 list_for_each_entry(mode_itr, modes, head) {
2325 if (mode_itr->expose_to_userspace &&
2326 drm_mode_match(mode_itr, mode,
2327 DRM_MODE_MATCH_TIMINGS |
2328 DRM_MODE_MATCH_CLOCK |
2329 DRM_MODE_MATCH_FLAGS |
2330 DRM_MODE_MATCH_3D_FLAGS))
2331 return false;
2332 }
2333 }
2334
2335 return true;
2336}
2337
2338int drm_mode_getconnector(struct drm_device *dev, void *data,
2339 struct drm_file *file_priv)
2340{
2341 struct drm_mode_get_connector *out_resp = data;
2342 struct drm_connector *connector;
2343 struct drm_encoder *encoder;
2344 struct drm_display_mode *mode;
2345 int mode_count = 0;
2346 int encoders_count = 0;
2347 int ret = 0;
2348 int copied = 0;
2349 struct drm_mode_modeinfo u_mode;
2350 struct drm_mode_modeinfo __user *mode_ptr;
2351 uint32_t __user *encoder_ptr;
2352
2353 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2354 return -EOPNOTSUPP;
2355
2356 memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
2357
2358 connector = drm_connector_lookup(dev, file_priv, out_resp->connector_id);
2359 if (!connector)
2360 return -ENOENT;
2361
2362 encoders_count = hweight32(connector->possible_encoders);
2363
2364 if ((out_resp->count_encoders >= encoders_count) && encoders_count) {
2365 copied = 0;
2366 encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr);
2367
2368 drm_connector_for_each_possible_encoder(connector, encoder) {
2369 if (put_user(encoder->base.id, encoder_ptr + copied)) {
2370 ret = -EFAULT;
2371 goto out;
2372 }
2373 copied++;
2374 }
2375 }
2376 out_resp->count_encoders = encoders_count;
2377
2378 out_resp->connector_id = connector->base.id;
2379 out_resp->connector_type = connector->connector_type;
2380 out_resp->connector_type_id = connector->connector_type_id;
2381
2382 mutex_lock(&dev->mode_config.mutex);
2383 if (out_resp->count_modes == 0) {
2384 connector->funcs->fill_modes(connector,
2385 dev->mode_config.max_width,
2386 dev->mode_config.max_height);
2387 }
2388
2389 out_resp->mm_width = connector->display_info.width_mm;
2390 out_resp->mm_height = connector->display_info.height_mm;
2391 out_resp->subpixel = connector->display_info.subpixel_order;
2392 out_resp->connection = connector->status;
2393
2394
2395 list_for_each_entry(mode, &connector->modes, head) {
2396 WARN_ON(mode->expose_to_userspace);
2397
2398 if (drm_mode_expose_to_userspace(mode, &connector->modes,
2399 file_priv)) {
2400 mode->expose_to_userspace = true;
2401 mode_count++;
2402 }
2403 }
2404
2405
2406
2407
2408
2409 if ((out_resp->count_modes >= mode_count) && mode_count) {
2410 copied = 0;
2411 mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr;
2412 list_for_each_entry(mode, &connector->modes, head) {
2413 if (!mode->expose_to_userspace)
2414 continue;
2415
2416
2417 mode->expose_to_userspace = false;
2418
2419 drm_mode_convert_to_umode(&u_mode, mode);
2420
2421
2422
2423
2424 if (!file_priv->aspect_ratio_allowed)
2425 u_mode.flags &= ~DRM_MODE_FLAG_PIC_AR_MASK;
2426 if (copy_to_user(mode_ptr + copied,
2427 &u_mode, sizeof(u_mode))) {
2428 ret = -EFAULT;
2429
2430
2431
2432
2433
2434 list_for_each_entry_continue(mode, &connector->modes, head)
2435 mode->expose_to_userspace = false;
2436
2437 mutex_unlock(&dev->mode_config.mutex);
2438
2439 goto out;
2440 }
2441 copied++;
2442 }
2443 } else {
2444
2445 list_for_each_entry(mode, &connector->modes, head)
2446 mode->expose_to_userspace = false;
2447 }
2448
2449 out_resp->count_modes = mode_count;
2450 mutex_unlock(&dev->mode_config.mutex);
2451
2452 drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
2453 encoder = drm_connector_get_encoder(connector);
2454 if (encoder)
2455 out_resp->encoder_id = encoder->base.id;
2456 else
2457 out_resp->encoder_id = 0;
2458
2459
2460
2461 ret = drm_mode_object_get_properties(&connector->base, file_priv->atomic,
2462 (uint32_t __user *)(unsigned long)(out_resp->props_ptr),
2463 (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr),
2464 &out_resp->count_props);
2465 drm_modeset_unlock(&dev->mode_config.connection_mutex);
2466
2467out:
2468 drm_connector_put(connector);
2469
2470 return ret;
2471}
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486static void drm_tile_group_free(struct kref *kref)
2487{
2488 struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount);
2489 struct drm_device *dev = tg->dev;
2490
2491 mutex_lock(&dev->mode_config.idr_mutex);
2492 idr_remove(&dev->mode_config.tile_idr, tg->id);
2493 mutex_unlock(&dev->mode_config.idr_mutex);
2494 kfree(tg);
2495}
2496
2497
2498
2499
2500
2501
2502
2503
2504void drm_mode_put_tile_group(struct drm_device *dev,
2505 struct drm_tile_group *tg)
2506{
2507 kref_put(&tg->refcount, drm_tile_group_free);
2508}
2509EXPORT_SYMBOL(drm_mode_put_tile_group);
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
2522 const char topology[8])
2523{
2524 struct drm_tile_group *tg;
2525 int id;
2526
2527 mutex_lock(&dev->mode_config.idr_mutex);
2528 idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) {
2529 if (!memcmp(tg->group_data, topology, 8)) {
2530 if (!kref_get_unless_zero(&tg->refcount))
2531 tg = NULL;
2532 mutex_unlock(&dev->mode_config.idr_mutex);
2533 return tg;
2534 }
2535 }
2536 mutex_unlock(&dev->mode_config.idr_mutex);
2537 return NULL;
2538}
2539EXPORT_SYMBOL(drm_mode_get_tile_group);
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
2553 const char topology[8])
2554{
2555 struct drm_tile_group *tg;
2556 int ret;
2557
2558 tg = kzalloc(sizeof(*tg), GFP_KERNEL);
2559 if (!tg)
2560 return NULL;
2561
2562 kref_init(&tg->refcount);
2563 memcpy(tg->group_data, topology, 8);
2564 tg->dev = dev;
2565
2566 mutex_lock(&dev->mode_config.idr_mutex);
2567 ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL);
2568 if (ret >= 0) {
2569 tg->id = ret;
2570 } else {
2571 kfree(tg);
2572 tg = NULL;
2573 }
2574
2575 mutex_unlock(&dev->mode_config.idr_mutex);
2576 return tg;
2577}
2578EXPORT_SYMBOL(drm_mode_create_tile_group);
2579