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/drmP.h>
24#include <drm/drm_connector.h>
25#include <drm/drm_edid.h>
26#include <drm/drm_encoder.h>
27
28#include "drm_crtc_internal.h"
29#include "drm_internal.h"
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
61struct drm_conn_prop_enum_list {
62 int type;
63 const char *name;
64 struct ida ida;
65};
66
67
68
69
70static struct drm_conn_prop_enum_list drm_connector_enum_list[] = {
71 { DRM_MODE_CONNECTOR_Unknown, "Unknown" },
72 { DRM_MODE_CONNECTOR_VGA, "VGA" },
73 { DRM_MODE_CONNECTOR_DVII, "DVI-I" },
74 { DRM_MODE_CONNECTOR_DVID, "DVI-D" },
75 { DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
76 { DRM_MODE_CONNECTOR_Composite, "Composite" },
77 { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" },
78 { DRM_MODE_CONNECTOR_LVDS, "LVDS" },
79 { DRM_MODE_CONNECTOR_Component, "Component" },
80 { DRM_MODE_CONNECTOR_9PinDIN, "DIN" },
81 { DRM_MODE_CONNECTOR_DisplayPort, "DP" },
82 { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
83 { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
84 { DRM_MODE_CONNECTOR_TV, "TV" },
85 { DRM_MODE_CONNECTOR_eDP, "eDP" },
86 { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
87 { DRM_MODE_CONNECTOR_DSI, "DSI" },
88 { DRM_MODE_CONNECTOR_DPI, "DPI" },
89};
90
91void drm_connector_ida_init(void)
92{
93 int i;
94
95 for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++)
96 ida_init(&drm_connector_enum_list[i].ida);
97}
98
99void drm_connector_ida_destroy(void)
100{
101 int i;
102
103 for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++)
104 ida_destroy(&drm_connector_enum_list[i].ida);
105}
106
107
108
109
110
111
112
113
114
115
116
117static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
118{
119 struct drm_cmdline_mode *mode = &connector->cmdline_mode;
120 char *option = NULL;
121
122 if (fb_get_options(connector->name, &option))
123 return;
124
125 if (!drm_mode_parse_command_line_for_connector(option,
126 connector,
127 mode))
128 return;
129
130 if (mode->force) {
131 DRM_INFO("forcing %s connector %s\n", connector->name,
132 drm_get_connector_force_name(mode->force));
133 connector->force = mode->force;
134 }
135
136 DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
137 connector->name,
138 mode->xres, mode->yres,
139 mode->refresh_specified ? mode->refresh : 60,
140 mode->rb ? " reduced blanking" : "",
141 mode->margins ? " with margins" : "",
142 mode->interlace ? " interlaced" : "");
143}
144
145static void drm_connector_free(struct kref *kref)
146{
147 struct drm_connector *connector =
148 container_of(kref, struct drm_connector, base.refcount);
149 struct drm_device *dev = connector->dev;
150
151 drm_mode_object_unregister(dev, &connector->base);
152 connector->funcs->destroy(connector);
153}
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168int drm_connector_init(struct drm_device *dev,
169 struct drm_connector *connector,
170 const struct drm_connector_funcs *funcs,
171 int connector_type)
172{
173 struct drm_mode_config *config = &dev->mode_config;
174 int ret;
175 struct ida *connector_ida =
176 &drm_connector_enum_list[connector_type].ida;
177
178 ret = __drm_mode_object_add(dev, &connector->base,
179 DRM_MODE_OBJECT_CONNECTOR,
180 false, drm_connector_free);
181 if (ret)
182 return ret;
183
184 connector->base.properties = &connector->properties;
185 connector->dev = dev;
186 connector->funcs = funcs;
187
188 ret = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL);
189 if (ret < 0)
190 goto out_put;
191 connector->index = ret;
192 ret = 0;
193
194 connector->connector_type = connector_type;
195 connector->connector_type_id =
196 ida_simple_get(connector_ida, 1, 0, GFP_KERNEL);
197 if (connector->connector_type_id < 0) {
198 ret = connector->connector_type_id;
199 goto out_put_id;
200 }
201 connector->name =
202 kasprintf(GFP_KERNEL, "%s-%d",
203 drm_connector_enum_list[connector_type].name,
204 connector->connector_type_id);
205 if (!connector->name) {
206 ret = -ENOMEM;
207 goto out_put_type_id;
208 }
209
210 INIT_LIST_HEAD(&connector->probed_modes);
211 INIT_LIST_HEAD(&connector->modes);
212 mutex_init(&connector->mutex);
213 connector->edid_blob_ptr = NULL;
214 connector->status = connector_status_unknown;
215
216 drm_connector_get_cmdline_mode(connector);
217
218
219
220 spin_lock_irq(&config->connector_list_lock);
221 list_add_tail(&connector->head, &config->connector_list);
222 config->num_connector++;
223 spin_unlock_irq(&config->connector_list_lock);
224
225 if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL)
226 drm_object_attach_property(&connector->base,
227 config->edid_property,
228 0);
229
230 drm_object_attach_property(&connector->base,
231 config->dpms_property, 0);
232
233 drm_object_attach_property(&connector->base,
234 config->link_status_property,
235 0);
236
237 if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
238 drm_object_attach_property(&connector->base, config->prop_crtc_id, 0);
239 }
240
241 connector->debugfs_entry = NULL;
242out_put_type_id:
243 if (ret)
244 ida_simple_remove(connector_ida, connector->connector_type_id);
245out_put_id:
246 if (ret)
247 ida_simple_remove(&config->connector_ida, connector->index);
248out_put:
249 if (ret)
250 drm_mode_object_unregister(dev, &connector->base);
251
252 return ret;
253}
254EXPORT_SYMBOL(drm_connector_init);
255
256
257
258
259
260
261
262
263
264
265
266
267
268int drm_mode_connector_attach_encoder(struct drm_connector *connector,
269 struct drm_encoder *encoder)
270{
271 int i;
272
273
274
275
276
277
278
279
280
281
282
283
284 if (WARN_ON(connector->encoder))
285 return -EINVAL;
286
287 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
288 if (connector->encoder_ids[i] == 0) {
289 connector->encoder_ids[i] = encoder->base.id;
290 return 0;
291 }
292 }
293 return -ENOMEM;
294}
295EXPORT_SYMBOL(drm_mode_connector_attach_encoder);
296
297static void drm_mode_remove(struct drm_connector *connector,
298 struct drm_display_mode *mode)
299{
300 list_del(&mode->head);
301 drm_mode_destroy(connector->dev, mode);
302}
303
304
305
306
307
308
309
310void drm_connector_cleanup(struct drm_connector *connector)
311{
312 struct drm_device *dev = connector->dev;
313 struct drm_display_mode *mode, *t;
314
315
316
317
318 if (WARN_ON(connector->registered))
319 drm_connector_unregister(connector);
320
321 if (connector->tile_group) {
322 drm_mode_put_tile_group(dev, connector->tile_group);
323 connector->tile_group = NULL;
324 }
325
326 list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
327 drm_mode_remove(connector, mode);
328
329 list_for_each_entry_safe(mode, t, &connector->modes, head)
330 drm_mode_remove(connector, mode);
331
332 ida_simple_remove(&drm_connector_enum_list[connector->connector_type].ida,
333 connector->connector_type_id);
334
335 ida_simple_remove(&dev->mode_config.connector_ida,
336 connector->index);
337
338 kfree(connector->display_info.bus_formats);
339 drm_mode_object_unregister(dev, &connector->base);
340 kfree(connector->name);
341 connector->name = NULL;
342 spin_lock_irq(&dev->mode_config.connector_list_lock);
343 list_del(&connector->head);
344 dev->mode_config.num_connector--;
345 spin_unlock_irq(&dev->mode_config.connector_list_lock);
346
347 WARN_ON(connector->state && !connector->funcs->atomic_destroy_state);
348 if (connector->state && connector->funcs->atomic_destroy_state)
349 connector->funcs->atomic_destroy_state(connector,
350 connector->state);
351
352 mutex_destroy(&connector->mutex);
353
354 memset(connector, 0, sizeof(*connector));
355}
356EXPORT_SYMBOL(drm_connector_cleanup);
357
358
359
360
361
362
363
364
365
366
367int drm_connector_register(struct drm_connector *connector)
368{
369 int ret = 0;
370
371 if (!connector->dev->registered)
372 return 0;
373
374 mutex_lock(&connector->mutex);
375 if (connector->registered)
376 goto unlock;
377
378 ret = drm_sysfs_connector_add(connector);
379 if (ret)
380 goto unlock;
381
382 ret = drm_debugfs_connector_add(connector);
383 if (ret) {
384 goto err_sysfs;
385 }
386
387 if (connector->funcs->late_register) {
388 ret = connector->funcs->late_register(connector);
389 if (ret)
390 goto err_debugfs;
391 }
392
393 drm_mode_object_register(connector->dev, &connector->base);
394
395 connector->registered = true;
396 goto unlock;
397
398err_debugfs:
399 drm_debugfs_connector_remove(connector);
400err_sysfs:
401 drm_sysfs_connector_remove(connector);
402unlock:
403 mutex_unlock(&connector->mutex);
404 return ret;
405}
406EXPORT_SYMBOL(drm_connector_register);
407
408
409
410
411
412
413
414void drm_connector_unregister(struct drm_connector *connector)
415{
416 mutex_lock(&connector->mutex);
417 if (!connector->registered) {
418 mutex_unlock(&connector->mutex);
419 return;
420 }
421
422 if (connector->funcs->early_unregister)
423 connector->funcs->early_unregister(connector);
424
425 drm_sysfs_connector_remove(connector);
426 drm_debugfs_connector_remove(connector);
427
428 connector->registered = false;
429 mutex_unlock(&connector->mutex);
430}
431EXPORT_SYMBOL(drm_connector_unregister);
432
433void drm_connector_unregister_all(struct drm_device *dev)
434{
435 struct drm_connector *connector;
436 struct drm_connector_list_iter conn_iter;
437
438 drm_connector_list_iter_begin(dev, &conn_iter);
439 drm_for_each_connector_iter(connector, &conn_iter)
440 drm_connector_unregister(connector);
441 drm_connector_list_iter_end(&conn_iter);
442}
443
444int drm_connector_register_all(struct drm_device *dev)
445{
446 struct drm_connector *connector;
447 struct drm_connector_list_iter conn_iter;
448 int ret = 0;
449
450 drm_connector_list_iter_begin(dev, &conn_iter);
451 drm_for_each_connector_iter(connector, &conn_iter) {
452 ret = drm_connector_register(connector);
453 if (ret)
454 break;
455 }
456 drm_connector_list_iter_end(&conn_iter);
457
458 if (ret)
459 drm_connector_unregister_all(dev);
460 return ret;
461}
462
463
464
465
466
467
468
469
470const char *drm_get_connector_status_name(enum drm_connector_status status)
471{
472 if (status == connector_status_connected)
473 return "connected";
474 else if (status == connector_status_disconnected)
475 return "disconnected";
476 else
477 return "unknown";
478}
479EXPORT_SYMBOL(drm_get_connector_status_name);
480
481
482
483
484
485
486
487const char *drm_get_connector_force_name(enum drm_connector_force force)
488{
489 switch (force) {
490 case DRM_FORCE_UNSPECIFIED:
491 return "unspecified";
492 case DRM_FORCE_OFF:
493 return "off";
494 case DRM_FORCE_ON:
495 return "on";
496 case DRM_FORCE_ON_DIGITAL:
497 return "digital";
498 default:
499 return "unknown";
500 }
501}
502
503#ifdef CONFIG_LOCKDEP
504static struct lockdep_map connector_list_iter_dep_map = {
505 .name = "drm_connector_list_iter"
506};
507#endif
508
509
510
511
512
513
514
515
516
517
518
519void drm_connector_list_iter_begin(struct drm_device *dev,
520 struct drm_connector_list_iter *iter)
521{
522 iter->dev = dev;
523 iter->conn = NULL;
524 lock_acquire_shared_recursive(&connector_list_iter_dep_map, 0, 1, NULL, _RET_IP_);
525}
526EXPORT_SYMBOL(drm_connector_list_iter_begin);
527
528
529
530
531
532
533
534
535struct drm_connector *
536drm_connector_list_iter_next(struct drm_connector_list_iter *iter)
537{
538 struct drm_connector *old_conn = iter->conn;
539 struct drm_mode_config *config = &iter->dev->mode_config;
540 struct list_head *lhead;
541 unsigned long flags;
542
543 spin_lock_irqsave(&config->connector_list_lock, flags);
544 lhead = old_conn ? &old_conn->head : &config->connector_list;
545
546 do {
547 if (lhead->next == &config->connector_list) {
548 iter->conn = NULL;
549 break;
550 }
551
552 lhead = lhead->next;
553 iter->conn = list_entry(lhead, struct drm_connector, head);
554
555
556 } while (!kref_get_unless_zero(&iter->conn->base.refcount));
557 spin_unlock_irqrestore(&config->connector_list_lock, flags);
558
559 if (old_conn)
560 drm_connector_put(old_conn);
561
562 return iter->conn;
563}
564EXPORT_SYMBOL(drm_connector_list_iter_next);
565
566
567
568
569
570
571
572
573
574
575void drm_connector_list_iter_end(struct drm_connector_list_iter *iter)
576{
577 iter->dev = NULL;
578 if (iter->conn)
579 drm_connector_put(iter->conn);
580 lock_release(&connector_list_iter_dep_map, 0, _RET_IP_);
581}
582EXPORT_SYMBOL(drm_connector_list_iter_end);
583
584static const struct drm_prop_enum_list drm_subpixel_enum_list[] = {
585 { SubPixelUnknown, "Unknown" },
586 { SubPixelHorizontalRGB, "Horizontal RGB" },
587 { SubPixelHorizontalBGR, "Horizontal BGR" },
588 { SubPixelVerticalRGB, "Vertical RGB" },
589 { SubPixelVerticalBGR, "Vertical BGR" },
590 { SubPixelNone, "None" },
591};
592
593
594
595
596
597
598
599
600const char *drm_get_subpixel_order_name(enum subpixel_order order)
601{
602 return drm_subpixel_enum_list[order].name;
603}
604EXPORT_SYMBOL(drm_get_subpixel_order_name);
605
606static const struct drm_prop_enum_list drm_dpms_enum_list[] = {
607 { DRM_MODE_DPMS_ON, "On" },
608 { DRM_MODE_DPMS_STANDBY, "Standby" },
609 { DRM_MODE_DPMS_SUSPEND, "Suspend" },
610 { DRM_MODE_DPMS_OFF, "Off" }
611};
612DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
613
614static const struct drm_prop_enum_list drm_link_status_enum_list[] = {
615 { DRM_MODE_LINK_STATUS_GOOD, "Good" },
616 { DRM_MODE_LINK_STATUS_BAD, "Bad" },
617};
618DRM_ENUM_NAME_FN(drm_get_link_status_name, drm_link_status_enum_list)
619
620
621
622
623
624
625
626
627
628
629
630int drm_display_info_set_bus_formats(struct drm_display_info *info,
631 const u32 *formats,
632 unsigned int num_formats)
633{
634 u32 *fmts = NULL;
635
636 if (!formats && num_formats)
637 return -EINVAL;
638
639 if (formats && num_formats) {
640 fmts = kmemdup(formats, sizeof(*formats) * num_formats,
641 GFP_KERNEL);
642 if (!fmts)
643 return -ENOMEM;
644 }
645
646 kfree(info->bus_formats);
647 info->bus_formats = fmts;
648 info->num_bus_formats = num_formats;
649
650 return 0;
651}
652EXPORT_SYMBOL(drm_display_info_set_bus_formats);
653
654
655static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = {
656 { DRM_MODE_SCALE_NONE, "None" },
657 { DRM_MODE_SCALE_FULLSCREEN, "Full" },
658 { DRM_MODE_SCALE_CENTER, "Center" },
659 { DRM_MODE_SCALE_ASPECT, "Full aspect" },
660};
661
662static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = {
663 { DRM_MODE_PICTURE_ASPECT_NONE, "Automatic" },
664 { DRM_MODE_PICTURE_ASPECT_4_3, "4:3" },
665 { DRM_MODE_PICTURE_ASPECT_16_9, "16:9" },
666};
667
668static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = {
669 { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" },
670 { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" },
671 { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" },
672};
673DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list)
674
675static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = {
676 { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" },
677 { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" },
678 { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" },
679};
680DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name,
681 drm_dvi_i_subconnector_enum_list)
682
683static const struct drm_prop_enum_list drm_tv_select_enum_list[] = {
684 { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" },
685 { DRM_MODE_SUBCONNECTOR_Composite, "Composite" },
686 { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" },
687 { DRM_MODE_SUBCONNECTOR_Component, "Component" },
688 { DRM_MODE_SUBCONNECTOR_SCART, "SCART" },
689};
690DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list)
691
692static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = {
693 { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" },
694 { DRM_MODE_SUBCONNECTOR_Composite, "Composite" },
695 { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" },
696 { DRM_MODE_SUBCONNECTOR_Component, "Component" },
697 { DRM_MODE_SUBCONNECTOR_SCART, "SCART" },
698};
699DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
700 drm_tv_subconnector_enum_list)
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
751int drm_connector_create_standard_properties(struct drm_device *dev)
752{
753 struct drm_property *prop;
754
755 prop = drm_property_create(dev, DRM_MODE_PROP_BLOB |
756 DRM_MODE_PROP_IMMUTABLE,
757 "EDID", 0);
758 if (!prop)
759 return -ENOMEM;
760 dev->mode_config.edid_property = prop;
761
762 prop = drm_property_create_enum(dev, 0,
763 "DPMS", drm_dpms_enum_list,
764 ARRAY_SIZE(drm_dpms_enum_list));
765 if (!prop)
766 return -ENOMEM;
767 dev->mode_config.dpms_property = prop;
768
769 prop = drm_property_create(dev,
770 DRM_MODE_PROP_BLOB |
771 DRM_MODE_PROP_IMMUTABLE,
772 "PATH", 0);
773 if (!prop)
774 return -ENOMEM;
775 dev->mode_config.path_property = prop;
776
777 prop = drm_property_create(dev,
778 DRM_MODE_PROP_BLOB |
779 DRM_MODE_PROP_IMMUTABLE,
780 "TILE", 0);
781 if (!prop)
782 return -ENOMEM;
783 dev->mode_config.tile_property = prop;
784
785 prop = drm_property_create_enum(dev, 0, "link-status",
786 drm_link_status_enum_list,
787 ARRAY_SIZE(drm_link_status_enum_list));
788 if (!prop)
789 return -ENOMEM;
790 dev->mode_config.link_status_property = prop;
791
792 return 0;
793}
794
795
796
797
798
799
800
801int drm_mode_create_dvi_i_properties(struct drm_device *dev)
802{
803 struct drm_property *dvi_i_selector;
804 struct drm_property *dvi_i_subconnector;
805
806 if (dev->mode_config.dvi_i_select_subconnector_property)
807 return 0;
808
809 dvi_i_selector =
810 drm_property_create_enum(dev, 0,
811 "select subconnector",
812 drm_dvi_i_select_enum_list,
813 ARRAY_SIZE(drm_dvi_i_select_enum_list));
814 dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector;
815
816 dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
817 "subconnector",
818 drm_dvi_i_subconnector_enum_list,
819 ARRAY_SIZE(drm_dvi_i_subconnector_enum_list));
820 dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector;
821
822 return 0;
823}
824EXPORT_SYMBOL(drm_mode_create_dvi_i_properties);
825
826
827
828
829
830
831
832
833
834
835
836
837int drm_mode_create_tv_properties(struct drm_device *dev,
838 unsigned int num_modes,
839 const char * const modes[])
840{
841 struct drm_property *tv_selector;
842 struct drm_property *tv_subconnector;
843 unsigned int i;
844
845 if (dev->mode_config.tv_select_subconnector_property)
846 return 0;
847
848
849
850
851 tv_selector = drm_property_create_enum(dev, 0,
852 "select subconnector",
853 drm_tv_select_enum_list,
854 ARRAY_SIZE(drm_tv_select_enum_list));
855 if (!tv_selector)
856 goto nomem;
857
858 dev->mode_config.tv_select_subconnector_property = tv_selector;
859
860 tv_subconnector =
861 drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
862 "subconnector",
863 drm_tv_subconnector_enum_list,
864 ARRAY_SIZE(drm_tv_subconnector_enum_list));
865 if (!tv_subconnector)
866 goto nomem;
867 dev->mode_config.tv_subconnector_property = tv_subconnector;
868
869
870
871
872 dev->mode_config.tv_left_margin_property =
873 drm_property_create_range(dev, 0, "left margin", 0, 100);
874 if (!dev->mode_config.tv_left_margin_property)
875 goto nomem;
876
877 dev->mode_config.tv_right_margin_property =
878 drm_property_create_range(dev, 0, "right margin", 0, 100);
879 if (!dev->mode_config.tv_right_margin_property)
880 goto nomem;
881
882 dev->mode_config.tv_top_margin_property =
883 drm_property_create_range(dev, 0, "top margin", 0, 100);
884 if (!dev->mode_config.tv_top_margin_property)
885 goto nomem;
886
887 dev->mode_config.tv_bottom_margin_property =
888 drm_property_create_range(dev, 0, "bottom margin", 0, 100);
889 if (!dev->mode_config.tv_bottom_margin_property)
890 goto nomem;
891
892 dev->mode_config.tv_mode_property =
893 drm_property_create(dev, DRM_MODE_PROP_ENUM,
894 "mode", num_modes);
895 if (!dev->mode_config.tv_mode_property)
896 goto nomem;
897
898 for (i = 0; i < num_modes; i++)
899 drm_property_add_enum(dev->mode_config.tv_mode_property, i,
900 i, modes[i]);
901
902 dev->mode_config.tv_brightness_property =
903 drm_property_create_range(dev, 0, "brightness", 0, 100);
904 if (!dev->mode_config.tv_brightness_property)
905 goto nomem;
906
907 dev->mode_config.tv_contrast_property =
908 drm_property_create_range(dev, 0, "contrast", 0, 100);
909 if (!dev->mode_config.tv_contrast_property)
910 goto nomem;
911
912 dev->mode_config.tv_flicker_reduction_property =
913 drm_property_create_range(dev, 0, "flicker reduction", 0, 100);
914 if (!dev->mode_config.tv_flicker_reduction_property)
915 goto nomem;
916
917 dev->mode_config.tv_overscan_property =
918 drm_property_create_range(dev, 0, "overscan", 0, 100);
919 if (!dev->mode_config.tv_overscan_property)
920 goto nomem;
921
922 dev->mode_config.tv_saturation_property =
923 drm_property_create_range(dev, 0, "saturation", 0, 100);
924 if (!dev->mode_config.tv_saturation_property)
925 goto nomem;
926
927 dev->mode_config.tv_hue_property =
928 drm_property_create_range(dev, 0, "hue", 0, 100);
929 if (!dev->mode_config.tv_hue_property)
930 goto nomem;
931
932 return 0;
933nomem:
934 return -ENOMEM;
935}
936EXPORT_SYMBOL(drm_mode_create_tv_properties);
937
938
939
940
941
942
943
944
945int drm_mode_create_scaling_mode_property(struct drm_device *dev)
946{
947 struct drm_property *scaling_mode;
948
949 if (dev->mode_config.scaling_mode_property)
950 return 0;
951
952 scaling_mode =
953 drm_property_create_enum(dev, 0, "scaling mode",
954 drm_scaling_mode_enum_list,
955 ARRAY_SIZE(drm_scaling_mode_enum_list));
956
957 dev->mode_config.scaling_mode_property = scaling_mode;
958
959 return 0;
960}
961EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
962
963
964
965
966
967
968
969
970
971
972
973int drm_mode_create_aspect_ratio_property(struct drm_device *dev)
974{
975 if (dev->mode_config.aspect_ratio_property)
976 return 0;
977
978 dev->mode_config.aspect_ratio_property =
979 drm_property_create_enum(dev, 0, "aspect ratio",
980 drm_aspect_ratio_enum_list,
981 ARRAY_SIZE(drm_aspect_ratio_enum_list));
982
983 if (dev->mode_config.aspect_ratio_property == NULL)
984 return -ENOMEM;
985
986 return 0;
987}
988EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property);
989
990
991
992
993
994
995
996int drm_mode_create_suggested_offset_properties(struct drm_device *dev)
997{
998 if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property)
999 return 0;
1000
1001 dev->mode_config.suggested_x_property =
1002 drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff);
1003
1004 dev->mode_config.suggested_y_property =
1005 drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff);
1006
1007 if (dev->mode_config.suggested_x_property == NULL ||
1008 dev->mode_config.suggested_y_property == NULL)
1009 return -ENOMEM;
1010 return 0;
1011}
1012EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties);
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027int drm_mode_connector_set_path_property(struct drm_connector *connector,
1028 const char *path)
1029{
1030 struct drm_device *dev = connector->dev;
1031 int ret;
1032
1033 ret = drm_property_replace_global_blob(dev,
1034 &connector->path_blob_ptr,
1035 strlen(path) + 1,
1036 path,
1037 &connector->base,
1038 dev->mode_config.path_property);
1039 return ret;
1040}
1041EXPORT_SYMBOL(drm_mode_connector_set_path_property);
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054int drm_mode_connector_set_tile_property(struct drm_connector *connector)
1055{
1056 struct drm_device *dev = connector->dev;
1057 char tile[256];
1058 int ret;
1059
1060 if (!connector->has_tile) {
1061 ret = drm_property_replace_global_blob(dev,
1062 &connector->tile_blob_ptr,
1063 0,
1064 NULL,
1065 &connector->base,
1066 dev->mode_config.tile_property);
1067 return ret;
1068 }
1069
1070 snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d",
1071 connector->tile_group->id, connector->tile_is_single_monitor,
1072 connector->num_h_tile, connector->num_v_tile,
1073 connector->tile_h_loc, connector->tile_v_loc,
1074 connector->tile_h_size, connector->tile_v_size);
1075
1076 ret = drm_property_replace_global_blob(dev,
1077 &connector->tile_blob_ptr,
1078 strlen(tile) + 1,
1079 tile,
1080 &connector->base,
1081 dev->mode_config.tile_property);
1082 return ret;
1083}
1084EXPORT_SYMBOL(drm_mode_connector_set_tile_property);
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097int drm_mode_connector_update_edid_property(struct drm_connector *connector,
1098 const struct edid *edid)
1099{
1100 struct drm_device *dev = connector->dev;
1101 size_t size = 0;
1102 int ret;
1103
1104
1105 if (connector->override_edid)
1106 return 0;
1107
1108 if (edid)
1109 size = EDID_LENGTH * (1 + edid->extensions);
1110
1111 ret = drm_property_replace_global_blob(dev,
1112 &connector->edid_blob_ptr,
1113 size,
1114 edid,
1115 &connector->base,
1116 dev->mode_config.edid_property);
1117 return ret;
1118}
1119EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140void drm_mode_connector_set_link_status_property(struct drm_connector *connector,
1141 uint64_t link_status)
1142{
1143 struct drm_device *dev = connector->dev;
1144
1145 drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
1146 connector->state->link_status = link_status;
1147 drm_modeset_unlock(&dev->mode_config.connection_mutex);
1148}
1149EXPORT_SYMBOL(drm_mode_connector_set_link_status_property);
1150
1151int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
1152 struct drm_property *property,
1153 uint64_t value)
1154{
1155 int ret = -EINVAL;
1156 struct drm_connector *connector = obj_to_connector(obj);
1157
1158
1159 if (property == connector->dev->mode_config.dpms_property) {
1160 ret = (*connector->funcs->dpms)(connector, (int)value);
1161 } else if (connector->funcs->set_property)
1162 ret = connector->funcs->set_property(connector, property, value);
1163
1164
1165 if (!ret)
1166 drm_object_property_set_value(&connector->base, property, value);
1167 return ret;
1168}
1169
1170int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
1171 void *data, struct drm_file *file_priv)
1172{
1173 struct drm_mode_connector_set_property *conn_set_prop = data;
1174 struct drm_mode_obj_set_property obj_set_prop = {
1175 .value = conn_set_prop->value,
1176 .prop_id = conn_set_prop->prop_id,
1177 .obj_id = conn_set_prop->connector_id,
1178 .obj_type = DRM_MODE_OBJECT_CONNECTOR
1179 };
1180
1181
1182 return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv);
1183}
1184
1185static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector)
1186{
1187
1188
1189 if (connector->state)
1190 return connector->state->best_encoder;
1191 return connector->encoder;
1192}
1193
1194static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
1195 const struct drm_file *file_priv)
1196{
1197
1198
1199
1200
1201 if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode))
1202 return false;
1203
1204 return true;
1205}
1206
1207int drm_mode_getconnector(struct drm_device *dev, void *data,
1208 struct drm_file *file_priv)
1209{
1210 struct drm_mode_get_connector *out_resp = data;
1211 struct drm_connector *connector;
1212 struct drm_encoder *encoder;
1213 struct drm_display_mode *mode;
1214 int mode_count = 0;
1215 int encoders_count = 0;
1216 int ret = 0;
1217 int copied = 0;
1218 int i;
1219 struct drm_mode_modeinfo u_mode;
1220 struct drm_mode_modeinfo __user *mode_ptr;
1221 uint32_t __user *encoder_ptr;
1222
1223 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1224 return -EINVAL;
1225
1226 memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
1227
1228 connector = drm_connector_lookup(dev, out_resp->connector_id);
1229 if (!connector)
1230 return -ENOENT;
1231
1232 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++)
1233 if (connector->encoder_ids[i] != 0)
1234 encoders_count++;
1235
1236 if ((out_resp->count_encoders >= encoders_count) && encoders_count) {
1237 copied = 0;
1238 encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr);
1239 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1240 if (connector->encoder_ids[i] != 0) {
1241 if (put_user(connector->encoder_ids[i],
1242 encoder_ptr + copied)) {
1243 ret = -EFAULT;
1244 goto out;
1245 }
1246 copied++;
1247 }
1248 }
1249 }
1250 out_resp->count_encoders = encoders_count;
1251
1252 out_resp->connector_id = connector->base.id;
1253 out_resp->connector_type = connector->connector_type;
1254 out_resp->connector_type_id = connector->connector_type_id;
1255
1256 mutex_lock(&dev->mode_config.mutex);
1257 if (out_resp->count_modes == 0) {
1258 connector->funcs->fill_modes(connector,
1259 dev->mode_config.max_width,
1260 dev->mode_config.max_height);
1261 }
1262
1263 out_resp->mm_width = connector->display_info.width_mm;
1264 out_resp->mm_height = connector->display_info.height_mm;
1265 out_resp->subpixel = connector->display_info.subpixel_order;
1266 out_resp->connection = connector->status;
1267
1268
1269 list_for_each_entry(mode, &connector->modes, head)
1270 if (drm_mode_expose_to_userspace(mode, file_priv))
1271 mode_count++;
1272
1273
1274
1275
1276
1277 if ((out_resp->count_modes >= mode_count) && mode_count) {
1278 copied = 0;
1279 mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr;
1280 list_for_each_entry(mode, &connector->modes, head) {
1281 if (!drm_mode_expose_to_userspace(mode, file_priv))
1282 continue;
1283
1284 drm_mode_convert_to_umode(&u_mode, mode);
1285 if (copy_to_user(mode_ptr + copied,
1286 &u_mode, sizeof(u_mode))) {
1287 ret = -EFAULT;
1288 mutex_unlock(&dev->mode_config.mutex);
1289
1290 goto out;
1291 }
1292 copied++;
1293 }
1294 }
1295 out_resp->count_modes = mode_count;
1296 mutex_unlock(&dev->mode_config.mutex);
1297
1298 drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
1299 encoder = drm_connector_get_encoder(connector);
1300 if (encoder)
1301 out_resp->encoder_id = encoder->base.id;
1302 else
1303 out_resp->encoder_id = 0;
1304
1305
1306
1307 ret = drm_mode_object_get_properties(&connector->base, file_priv->atomic,
1308 (uint32_t __user *)(unsigned long)(out_resp->props_ptr),
1309 (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr),
1310 &out_resp->count_props);
1311 drm_modeset_unlock(&dev->mode_config.connection_mutex);
1312
1313out:
1314 drm_connector_put(connector);
1315
1316 return ret;
1317}
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332static void drm_tile_group_free(struct kref *kref)
1333{
1334 struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount);
1335 struct drm_device *dev = tg->dev;
1336 mutex_lock(&dev->mode_config.idr_mutex);
1337 idr_remove(&dev->mode_config.tile_idr, tg->id);
1338 mutex_unlock(&dev->mode_config.idr_mutex);
1339 kfree(tg);
1340}
1341
1342
1343
1344
1345
1346
1347
1348
1349void drm_mode_put_tile_group(struct drm_device *dev,
1350 struct drm_tile_group *tg)
1351{
1352 kref_put(&tg->refcount, drm_tile_group_free);
1353}
1354EXPORT_SYMBOL(drm_mode_put_tile_group);
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
1367 char topology[8])
1368{
1369 struct drm_tile_group *tg;
1370 int id;
1371 mutex_lock(&dev->mode_config.idr_mutex);
1372 idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) {
1373 if (!memcmp(tg->group_data, topology, 8)) {
1374 if (!kref_get_unless_zero(&tg->refcount))
1375 tg = NULL;
1376 mutex_unlock(&dev->mode_config.idr_mutex);
1377 return tg;
1378 }
1379 }
1380 mutex_unlock(&dev->mode_config.idr_mutex);
1381 return NULL;
1382}
1383EXPORT_SYMBOL(drm_mode_get_tile_group);
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
1397 char topology[8])
1398{
1399 struct drm_tile_group *tg;
1400 int ret;
1401
1402 tg = kzalloc(sizeof(*tg), GFP_KERNEL);
1403 if (!tg)
1404 return ERR_PTR(-ENOMEM);
1405
1406 kref_init(&tg->refcount);
1407 memcpy(tg->group_data, topology, 8);
1408 tg->dev = dev;
1409
1410 mutex_lock(&dev->mode_config.idr_mutex);
1411 ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL);
1412 if (ret >= 0) {
1413 tg->id = ret;
1414 } else {
1415 kfree(tg);
1416 tg = ERR_PTR(ret);
1417 }
1418
1419 mutex_unlock(&dev->mode_config.idr_mutex);
1420 return tg;
1421}
1422EXPORT_SYMBOL(drm_mode_create_tile_group);
1423