diff options
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 717 |
1 files changed, 299 insertions, 418 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 0e3cc66aa8b7..f1d9f0569d7f 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <drm/drm_fourcc.h> | 39 | #include <drm/drm_fourcc.h> |
40 | #include <drm/drm_modeset_lock.h> | 40 | #include <drm/drm_modeset_lock.h> |
41 | #include <drm/drm_atomic.h> | 41 | #include <drm/drm_atomic.h> |
42 | #include <drm/drm_auth.h> | ||
42 | 43 | ||
43 | #include "drm_crtc_internal.h" | 44 | #include "drm_crtc_internal.h" |
44 | #include "drm_internal.h" | 45 | #include "drm_internal.h" |
@@ -239,37 +240,6 @@ const char *drm_get_subpixel_order_name(enum subpixel_order order) | |||
239 | } | 240 | } |
240 | EXPORT_SYMBOL(drm_get_subpixel_order_name); | 241 | EXPORT_SYMBOL(drm_get_subpixel_order_name); |
241 | 242 | ||
242 | static char printable_char(int c) | ||
243 | { | ||
244 | return isascii(c) && isprint(c) ? c : '?'; | ||
245 | } | ||
246 | |||
247 | /** | ||
248 | * drm_get_format_name - return a string for drm fourcc format | ||
249 | * @format: format to compute name of | ||
250 | * | ||
251 | * Note that the buffer used by this function is globally shared and owned by | ||
252 | * the function itself. | ||
253 | * | ||
254 | * FIXME: This isn't really multithreading safe. | ||
255 | */ | ||
256 | const char *drm_get_format_name(uint32_t format) | ||
257 | { | ||
258 | static char buf[32]; | ||
259 | |||
260 | snprintf(buf, sizeof(buf), | ||
261 | "%c%c%c%c %s-endian (0x%08x)", | ||
262 | printable_char(format & 0xff), | ||
263 | printable_char((format >> 8) & 0xff), | ||
264 | printable_char((format >> 16) & 0xff), | ||
265 | printable_char((format >> 24) & 0x7f), | ||
266 | format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little", | ||
267 | format); | ||
268 | |||
269 | return buf; | ||
270 | } | ||
271 | EXPORT_SYMBOL(drm_get_format_name); | ||
272 | |||
273 | /* | 243 | /* |
274 | * Internal function to assign a slot in the object idr and optionally | 244 | * Internal function to assign a slot in the object idr and optionally |
275 | * register the object into the idr. | 245 | * register the object into the idr. |
@@ -426,6 +396,51 @@ void drm_mode_object_reference(struct drm_mode_object *obj) | |||
426 | } | 396 | } |
427 | EXPORT_SYMBOL(drm_mode_object_reference); | 397 | EXPORT_SYMBOL(drm_mode_object_reference); |
428 | 398 | ||
399 | /** | ||
400 | * drm_crtc_force_disable - Forcibly turn off a CRTC | ||
401 | * @crtc: CRTC to turn off | ||
402 | * | ||
403 | * Returns: | ||
404 | * Zero on success, error code on failure. | ||
405 | */ | ||
406 | int drm_crtc_force_disable(struct drm_crtc *crtc) | ||
407 | { | ||
408 | struct drm_mode_set set = { | ||
409 | .crtc = crtc, | ||
410 | }; | ||
411 | |||
412 | return drm_mode_set_config_internal(&set); | ||
413 | } | ||
414 | EXPORT_SYMBOL(drm_crtc_force_disable); | ||
415 | |||
416 | /** | ||
417 | * drm_crtc_force_disable_all - Forcibly turn off all enabled CRTCs | ||
418 | * @dev: DRM device whose CRTCs to turn off | ||
419 | * | ||
420 | * Drivers may want to call this on unload to ensure that all displays are | ||
421 | * unlit and the GPU is in a consistent, low power state. Takes modeset locks. | ||
422 | * | ||
423 | * Returns: | ||
424 | * Zero on success, error code on failure. | ||
425 | */ | ||
426 | int drm_crtc_force_disable_all(struct drm_device *dev) | ||
427 | { | ||
428 | struct drm_crtc *crtc; | ||
429 | int ret = 0; | ||
430 | |||
431 | drm_modeset_lock_all(dev); | ||
432 | drm_for_each_crtc(crtc, dev) | ||
433 | if (crtc->enabled) { | ||
434 | ret = drm_crtc_force_disable(crtc); | ||
435 | if (ret) | ||
436 | goto out; | ||
437 | } | ||
438 | out: | ||
439 | drm_modeset_unlock_all(dev); | ||
440 | return ret; | ||
441 | } | ||
442 | EXPORT_SYMBOL(drm_crtc_force_disable_all); | ||
443 | |||
429 | static void drm_framebuffer_free(struct kref *kref) | 444 | static void drm_framebuffer_free(struct kref *kref) |
430 | { | 445 | { |
431 | struct drm_framebuffer *fb = | 446 | struct drm_framebuffer *fb = |
@@ -535,7 +550,7 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private); | |||
535 | * | 550 | * |
536 | * Cleanup framebuffer. This function is intended to be used from the drivers | 551 | * Cleanup framebuffer. This function is intended to be used from the drivers |
537 | * ->destroy callback. It can also be used to clean up driver private | 552 | * ->destroy callback. It can also be used to clean up driver private |
538 | * framebuffers embedded into a larger structure. | 553 | * framebuffers embedded into a larger structure. |
539 | * | 554 | * |
540 | * Note that this function does not remove the fb from active usuage - if it is | 555 | * Note that this function does not remove the fb from active usuage - if it is |
541 | * still used anywhere, hilarity can ensue since userspace could call getfb on | 556 | * still used anywhere, hilarity can ensue since userspace could call getfb on |
@@ -574,8 +589,6 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) | |||
574 | struct drm_device *dev; | 589 | struct drm_device *dev; |
575 | struct drm_crtc *crtc; | 590 | struct drm_crtc *crtc; |
576 | struct drm_plane *plane; | 591 | struct drm_plane *plane; |
577 | struct drm_mode_set set; | ||
578 | int ret; | ||
579 | 592 | ||
580 | if (!fb) | 593 | if (!fb) |
581 | return; | 594 | return; |
@@ -605,11 +618,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) | |||
605 | drm_for_each_crtc(crtc, dev) { | 618 | drm_for_each_crtc(crtc, dev) { |
606 | if (crtc->primary->fb == fb) { | 619 | if (crtc->primary->fb == fb) { |
607 | /* should turn off the crtc */ | 620 | /* should turn off the crtc */ |
608 | memset(&set, 0, sizeof(struct drm_mode_set)); | 621 | if (drm_crtc_force_disable(crtc)) |
609 | set.crtc = crtc; | ||
610 | set.fb = NULL; | ||
611 | ret = drm_mode_set_config_internal(&set); | ||
612 | if (ret) | ||
613 | DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); | 622 | DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); |
614 | } | 623 | } |
615 | } | 624 | } |
@@ -639,6 +648,31 @@ static unsigned int drm_num_crtcs(struct drm_device *dev) | |||
639 | return num; | 648 | return num; |
640 | } | 649 | } |
641 | 650 | ||
651 | static int drm_crtc_register_all(struct drm_device *dev) | ||
652 | { | ||
653 | struct drm_crtc *crtc; | ||
654 | int ret = 0; | ||
655 | |||
656 | drm_for_each_crtc(crtc, dev) { | ||
657 | if (crtc->funcs->late_register) | ||
658 | ret = crtc->funcs->late_register(crtc); | ||
659 | if (ret) | ||
660 | return ret; | ||
661 | } | ||
662 | |||
663 | return 0; | ||
664 | } | ||
665 | |||
666 | static void drm_crtc_unregister_all(struct drm_device *dev) | ||
667 | { | ||
668 | struct drm_crtc *crtc; | ||
669 | |||
670 | drm_for_each_crtc(crtc, dev) { | ||
671 | if (crtc->funcs->early_unregister) | ||
672 | crtc->funcs->early_unregister(crtc); | ||
673 | } | ||
674 | } | ||
675 | |||
642 | /** | 676 | /** |
643 | * drm_crtc_init_with_planes - Initialise a new CRTC object with | 677 | * drm_crtc_init_with_planes - Initialise a new CRTC object with |
644 | * specified primary and cursor planes. | 678 | * specified primary and cursor planes. |
@@ -669,6 +703,9 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, | |||
669 | crtc->dev = dev; | 703 | crtc->dev = dev; |
670 | crtc->funcs = funcs; | 704 | crtc->funcs = funcs; |
671 | 705 | ||
706 | INIT_LIST_HEAD(&crtc->commit_list); | ||
707 | spin_lock_init(&crtc->commit_lock); | ||
708 | |||
672 | drm_modeset_lock_init(&crtc->mutex); | 709 | drm_modeset_lock_init(&crtc->mutex); |
673 | ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); | 710 | ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); |
674 | if (ret) | 711 | if (ret) |
@@ -692,7 +729,7 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, | |||
692 | crtc->base.properties = &crtc->properties; | 729 | crtc->base.properties = &crtc->properties; |
693 | 730 | ||
694 | list_add_tail(&crtc->head, &config->crtc_list); | 731 | list_add_tail(&crtc->head, &config->crtc_list); |
695 | config->num_crtc++; | 732 | crtc->index = config->num_crtc++; |
696 | 733 | ||
697 | crtc->primary = primary; | 734 | crtc->primary = primary; |
698 | crtc->cursor = cursor; | 735 | crtc->cursor = cursor; |
@@ -722,6 +759,11 @@ void drm_crtc_cleanup(struct drm_crtc *crtc) | |||
722 | { | 759 | { |
723 | struct drm_device *dev = crtc->dev; | 760 | struct drm_device *dev = crtc->dev; |
724 | 761 | ||
762 | /* Note that the crtc_list is considered to be static; should we | ||
763 | * remove the drm_crtc at runtime we would have to decrement all | ||
764 | * the indices on the drm_crtc after us in the crtc_list. | ||
765 | */ | ||
766 | |||
725 | kfree(crtc->gamma_store); | 767 | kfree(crtc->gamma_store); |
726 | crtc->gamma_store = NULL; | 768 | crtc->gamma_store = NULL; |
727 | 769 | ||
@@ -741,29 +783,6 @@ void drm_crtc_cleanup(struct drm_crtc *crtc) | |||
741 | } | 783 | } |
742 | EXPORT_SYMBOL(drm_crtc_cleanup); | 784 | EXPORT_SYMBOL(drm_crtc_cleanup); |
743 | 785 | ||
744 | /** | ||
745 | * drm_crtc_index - find the index of a registered CRTC | ||
746 | * @crtc: CRTC to find index for | ||
747 | * | ||
748 | * Given a registered CRTC, return the index of that CRTC within a DRM | ||
749 | * device's list of CRTCs. | ||
750 | */ | ||
751 | unsigned int drm_crtc_index(struct drm_crtc *crtc) | ||
752 | { | ||
753 | unsigned int index = 0; | ||
754 | struct drm_crtc *tmp; | ||
755 | |||
756 | drm_for_each_crtc(tmp, crtc->dev) { | ||
757 | if (tmp == crtc) | ||
758 | return index; | ||
759 | |||
760 | index++; | ||
761 | } | ||
762 | |||
763 | BUG(); | ||
764 | } | ||
765 | EXPORT_SYMBOL(drm_crtc_index); | ||
766 | |||
767 | /* | 786 | /* |
768 | * drm_mode_remove - remove and free a mode | 787 | * drm_mode_remove - remove and free a mode |
769 | * @connector: connector list to modify | 788 | * @connector: connector list to modify |
@@ -909,11 +928,11 @@ int drm_connector_init(struct drm_device *dev, | |||
909 | connector->dev = dev; | 928 | connector->dev = dev; |
910 | connector->funcs = funcs; | 929 | connector->funcs = funcs; |
911 | 930 | ||
912 | connector->connector_id = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL); | 931 | ret = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL); |
913 | if (connector->connector_id < 0) { | 932 | if (ret < 0) |
914 | ret = connector->connector_id; | ||
915 | goto out_put; | 933 | goto out_put; |
916 | } | 934 | connector->index = ret; |
935 | ret = 0; | ||
917 | 936 | ||
918 | connector->connector_type = connector_type; | 937 | connector->connector_type = connector_type; |
919 | connector->connector_type_id = | 938 | connector->connector_type_id = |
@@ -961,7 +980,7 @@ out_put_type_id: | |||
961 | ida_remove(connector_ida, connector->connector_type_id); | 980 | ida_remove(connector_ida, connector->connector_type_id); |
962 | out_put_id: | 981 | out_put_id: |
963 | if (ret) | 982 | if (ret) |
964 | ida_remove(&config->connector_ida, connector->connector_id); | 983 | ida_remove(&config->connector_ida, connector->index); |
965 | out_put: | 984 | out_put: |
966 | if (ret) | 985 | if (ret) |
967 | drm_mode_object_unregister(dev, &connector->base); | 986 | drm_mode_object_unregister(dev, &connector->base); |
@@ -984,6 +1003,12 @@ void drm_connector_cleanup(struct drm_connector *connector) | |||
984 | struct drm_device *dev = connector->dev; | 1003 | struct drm_device *dev = connector->dev; |
985 | struct drm_display_mode *mode, *t; | 1004 | struct drm_display_mode *mode, *t; |
986 | 1005 | ||
1006 | /* The connector should have been removed from userspace long before | ||
1007 | * it is finally destroyed. | ||
1008 | */ | ||
1009 | if (WARN_ON(connector->registered)) | ||
1010 | drm_connector_unregister(connector); | ||
1011 | |||
987 | if (connector->tile_group) { | 1012 | if (connector->tile_group) { |
988 | drm_mode_put_tile_group(dev, connector->tile_group); | 1013 | drm_mode_put_tile_group(dev, connector->tile_group); |
989 | connector->tile_group = NULL; | 1014 | connector->tile_group = NULL; |
@@ -999,7 +1024,7 @@ void drm_connector_cleanup(struct drm_connector *connector) | |||
999 | connector->connector_type_id); | 1024 | connector->connector_type_id); |
1000 | 1025 | ||
1001 | ida_remove(&dev->mode_config.connector_ida, | 1026 | ida_remove(&dev->mode_config.connector_ida, |
1002 | connector->connector_id); | 1027 | connector->index); |
1003 | 1028 | ||
1004 | kfree(connector->display_info.bus_formats); | 1029 | kfree(connector->display_info.bus_formats); |
1005 | drm_mode_object_unregister(dev, &connector->base); | 1030 | drm_mode_object_unregister(dev, &connector->base); |
@@ -1030,19 +1055,34 @@ int drm_connector_register(struct drm_connector *connector) | |||
1030 | { | 1055 | { |
1031 | int ret; | 1056 | int ret; |
1032 | 1057 | ||
1058 | if (connector->registered) | ||
1059 | return 0; | ||
1060 | |||
1033 | ret = drm_sysfs_connector_add(connector); | 1061 | ret = drm_sysfs_connector_add(connector); |
1034 | if (ret) | 1062 | if (ret) |
1035 | return ret; | 1063 | return ret; |
1036 | 1064 | ||
1037 | ret = drm_debugfs_connector_add(connector); | 1065 | ret = drm_debugfs_connector_add(connector); |
1038 | if (ret) { | 1066 | if (ret) { |
1039 | drm_sysfs_connector_remove(connector); | 1067 | goto err_sysfs; |
1040 | return ret; | 1068 | } |
1069 | |||
1070 | if (connector->funcs->late_register) { | ||
1071 | ret = connector->funcs->late_register(connector); | ||
1072 | if (ret) | ||
1073 | goto err_debugfs; | ||
1041 | } | 1074 | } |
1042 | 1075 | ||
1043 | drm_mode_object_register(connector->dev, &connector->base); | 1076 | drm_mode_object_register(connector->dev, &connector->base); |
1044 | 1077 | ||
1078 | connector->registered = true; | ||
1045 | return 0; | 1079 | return 0; |
1080 | |||
1081 | err_debugfs: | ||
1082 | drm_debugfs_connector_remove(connector); | ||
1083 | err_sysfs: | ||
1084 | drm_sysfs_connector_remove(connector); | ||
1085 | return ret; | ||
1046 | } | 1086 | } |
1047 | EXPORT_SYMBOL(drm_connector_register); | 1087 | EXPORT_SYMBOL(drm_connector_register); |
1048 | 1088 | ||
@@ -1054,28 +1094,29 @@ EXPORT_SYMBOL(drm_connector_register); | |||
1054 | */ | 1094 | */ |
1055 | void drm_connector_unregister(struct drm_connector *connector) | 1095 | void drm_connector_unregister(struct drm_connector *connector) |
1056 | { | 1096 | { |
1097 | if (!connector->registered) | ||
1098 | return; | ||
1099 | |||
1100 | if (connector->funcs->early_unregister) | ||
1101 | connector->funcs->early_unregister(connector); | ||
1102 | |||
1057 | drm_sysfs_connector_remove(connector); | 1103 | drm_sysfs_connector_remove(connector); |
1058 | drm_debugfs_connector_remove(connector); | 1104 | drm_debugfs_connector_remove(connector); |
1105 | |||
1106 | connector->registered = false; | ||
1059 | } | 1107 | } |
1060 | EXPORT_SYMBOL(drm_connector_unregister); | 1108 | EXPORT_SYMBOL(drm_connector_unregister); |
1061 | 1109 | ||
1062 | /** | 1110 | static void drm_connector_unregister_all(struct drm_device *dev) |
1063 | * drm_connector_register_all - register all connectors | 1111 | { |
1064 | * @dev: drm device | 1112 | struct drm_connector *connector; |
1065 | * | 1113 | |
1066 | * This function registers all connectors in sysfs and other places so that | 1114 | /* FIXME: taking the mode config mutex ends up in a clash with sysfs */ |
1067 | * userspace can start to access them. Drivers can call it after calling | 1115 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) |
1068 | * drm_dev_register() to complete the device registration, if they don't call | 1116 | drm_connector_unregister(connector); |
1069 | * drm_connector_register() on each connector individually. | 1117 | } |
1070 | * | 1118 | |
1071 | * When a device is unplugged and should be removed from userspace access, | 1119 | static int drm_connector_register_all(struct drm_device *dev) |
1072 | * call drm_connector_unregister_all(), which is the inverse of this | ||
1073 | * function. | ||
1074 | * | ||
1075 | * Returns: | ||
1076 | * Zero on success, error code on failure. | ||
1077 | */ | ||
1078 | int drm_connector_register_all(struct drm_device *dev) | ||
1079 | { | 1120 | { |
1080 | struct drm_connector *connector; | 1121 | struct drm_connector *connector; |
1081 | int ret; | 1122 | int ret; |
@@ -1097,27 +1138,31 @@ err: | |||
1097 | drm_connector_unregister_all(dev); | 1138 | drm_connector_unregister_all(dev); |
1098 | return ret; | 1139 | return ret; |
1099 | } | 1140 | } |
1100 | EXPORT_SYMBOL(drm_connector_register_all); | ||
1101 | 1141 | ||
1102 | /** | 1142 | static int drm_encoder_register_all(struct drm_device *dev) |
1103 | * drm_connector_unregister_all - unregister connector userspace interfaces | ||
1104 | * @dev: drm device | ||
1105 | * | ||
1106 | * This functions unregisters all connectors from sysfs and other places so | ||
1107 | * that userspace can no longer access them. Drivers should call this as the | ||
1108 | * first step tearing down the device instace, or when the underlying | ||
1109 | * physical device disappeared (e.g. USB unplug), right before calling | ||
1110 | * drm_dev_unregister(). | ||
1111 | */ | ||
1112 | void drm_connector_unregister_all(struct drm_device *dev) | ||
1113 | { | 1143 | { |
1114 | struct drm_connector *connector; | 1144 | struct drm_encoder *encoder; |
1145 | int ret = 0; | ||
1115 | 1146 | ||
1116 | /* FIXME: taking the mode config mutex ends up in a clash with sysfs */ | 1147 | drm_for_each_encoder(encoder, dev) { |
1117 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) | 1148 | if (encoder->funcs->late_register) |
1118 | drm_connector_unregister(connector); | 1149 | ret = encoder->funcs->late_register(encoder); |
1150 | if (ret) | ||
1151 | return ret; | ||
1152 | } | ||
1153 | |||
1154 | return 0; | ||
1155 | } | ||
1156 | |||
1157 | static void drm_encoder_unregister_all(struct drm_device *dev) | ||
1158 | { | ||
1159 | struct drm_encoder *encoder; | ||
1160 | |||
1161 | drm_for_each_encoder(encoder, dev) { | ||
1162 | if (encoder->funcs->early_unregister) | ||
1163 | encoder->funcs->early_unregister(encoder); | ||
1164 | } | ||
1119 | } | 1165 | } |
1120 | EXPORT_SYMBOL(drm_connector_unregister_all); | ||
1121 | 1166 | ||
1122 | /** | 1167 | /** |
1123 | * drm_encoder_init - Init a preallocated encoder | 1168 | * drm_encoder_init - Init a preallocated encoder |
@@ -1166,7 +1211,7 @@ int drm_encoder_init(struct drm_device *dev, | |||
1166 | } | 1211 | } |
1167 | 1212 | ||
1168 | list_add_tail(&encoder->head, &dev->mode_config.encoder_list); | 1213 | list_add_tail(&encoder->head, &dev->mode_config.encoder_list); |
1169 | dev->mode_config.num_encoder++; | 1214 | encoder->index = dev->mode_config.num_encoder++; |
1170 | 1215 | ||
1171 | out_put: | 1216 | out_put: |
1172 | if (ret) | 1217 | if (ret) |
@@ -1180,29 +1225,6 @@ out_unlock: | |||
1180 | EXPORT_SYMBOL(drm_encoder_init); | 1225 | EXPORT_SYMBOL(drm_encoder_init); |
1181 | 1226 | ||
1182 | /** | 1227 | /** |
1183 | * drm_encoder_index - find the index of a registered encoder | ||
1184 | * @encoder: encoder to find index for | ||
1185 | * | ||
1186 | * Given a registered encoder, return the index of that encoder within a DRM | ||
1187 | * device's list of encoders. | ||
1188 | */ | ||
1189 | unsigned int drm_encoder_index(struct drm_encoder *encoder) | ||
1190 | { | ||
1191 | unsigned int index = 0; | ||
1192 | struct drm_encoder *tmp; | ||
1193 | |||
1194 | drm_for_each_encoder(tmp, encoder->dev) { | ||
1195 | if (tmp == encoder) | ||
1196 | return index; | ||
1197 | |||
1198 | index++; | ||
1199 | } | ||
1200 | |||
1201 | BUG(); | ||
1202 | } | ||
1203 | EXPORT_SYMBOL(drm_encoder_index); | ||
1204 | |||
1205 | /** | ||
1206 | * drm_encoder_cleanup - cleans up an initialised encoder | 1228 | * drm_encoder_cleanup - cleans up an initialised encoder |
1207 | * @encoder: encoder to cleanup | 1229 | * @encoder: encoder to cleanup |
1208 | * | 1230 | * |
@@ -1212,6 +1234,11 @@ void drm_encoder_cleanup(struct drm_encoder *encoder) | |||
1212 | { | 1234 | { |
1213 | struct drm_device *dev = encoder->dev; | 1235 | struct drm_device *dev = encoder->dev; |
1214 | 1236 | ||
1237 | /* Note that the encoder_list is considered to be static; should we | ||
1238 | * remove the drm_encoder at runtime we would have to decrement all | ||
1239 | * the indices on the drm_encoder after us in the encoder_list. | ||
1240 | */ | ||
1241 | |||
1215 | drm_modeset_lock_all(dev); | 1242 | drm_modeset_lock_all(dev); |
1216 | drm_mode_object_unregister(dev, &encoder->base); | 1243 | drm_mode_object_unregister(dev, &encoder->base); |
1217 | kfree(encoder->name); | 1244 | kfree(encoder->name); |
@@ -1300,7 +1327,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, | |||
1300 | plane->type = type; | 1327 | plane->type = type; |
1301 | 1328 | ||
1302 | list_add_tail(&plane->head, &config->plane_list); | 1329 | list_add_tail(&plane->head, &config->plane_list); |
1303 | config->num_total_plane++; | 1330 | plane->index = config->num_total_plane++; |
1304 | if (plane->type == DRM_PLANE_TYPE_OVERLAY) | 1331 | if (plane->type == DRM_PLANE_TYPE_OVERLAY) |
1305 | config->num_overlay_plane++; | 1332 | config->num_overlay_plane++; |
1306 | 1333 | ||
@@ -1325,6 +1352,31 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, | |||
1325 | } | 1352 | } |
1326 | EXPORT_SYMBOL(drm_universal_plane_init); | 1353 | EXPORT_SYMBOL(drm_universal_plane_init); |
1327 | 1354 | ||
1355 | static int drm_plane_register_all(struct drm_device *dev) | ||
1356 | { | ||
1357 | struct drm_plane *plane; | ||
1358 | int ret = 0; | ||
1359 | |||
1360 | drm_for_each_plane(plane, dev) { | ||
1361 | if (plane->funcs->late_register) | ||
1362 | ret = plane->funcs->late_register(plane); | ||
1363 | if (ret) | ||
1364 | return ret; | ||
1365 | } | ||
1366 | |||
1367 | return 0; | ||
1368 | } | ||
1369 | |||
1370 | static void drm_plane_unregister_all(struct drm_device *dev) | ||
1371 | { | ||
1372 | struct drm_plane *plane; | ||
1373 | |||
1374 | drm_for_each_plane(plane, dev) { | ||
1375 | if (plane->funcs->early_unregister) | ||
1376 | plane->funcs->early_unregister(plane); | ||
1377 | } | ||
1378 | } | ||
1379 | |||
1328 | /** | 1380 | /** |
1329 | * drm_plane_init - Initialize a legacy plane | 1381 | * drm_plane_init - Initialize a legacy plane |
1330 | * @dev: DRM device | 1382 | * @dev: DRM device |
@@ -1374,6 +1426,11 @@ void drm_plane_cleanup(struct drm_plane *plane) | |||
1374 | 1426 | ||
1375 | BUG_ON(list_empty(&plane->head)); | 1427 | BUG_ON(list_empty(&plane->head)); |
1376 | 1428 | ||
1429 | /* Note that the plane_list is considered to be static; should we | ||
1430 | * remove the drm_plane at runtime we would have to decrement all | ||
1431 | * the indices on the drm_plane after us in the plane_list. | ||
1432 | */ | ||
1433 | |||
1377 | list_del(&plane->head); | 1434 | list_del(&plane->head); |
1378 | dev->mode_config.num_total_plane--; | 1435 | dev->mode_config.num_total_plane--; |
1379 | if (plane->type == DRM_PLANE_TYPE_OVERLAY) | 1436 | if (plane->type == DRM_PLANE_TYPE_OVERLAY) |
@@ -1391,29 +1448,6 @@ void drm_plane_cleanup(struct drm_plane *plane) | |||
1391 | EXPORT_SYMBOL(drm_plane_cleanup); | 1448 | EXPORT_SYMBOL(drm_plane_cleanup); |
1392 | 1449 | ||
1393 | /** | 1450 | /** |
1394 | * drm_plane_index - find the index of a registered plane | ||
1395 | * @plane: plane to find index for | ||
1396 | * | ||
1397 | * Given a registered plane, return the index of that CRTC within a DRM | ||
1398 | * device's list of planes. | ||
1399 | */ | ||
1400 | unsigned int drm_plane_index(struct drm_plane *plane) | ||
1401 | { | ||
1402 | unsigned int index = 0; | ||
1403 | struct drm_plane *tmp; | ||
1404 | |||
1405 | drm_for_each_plane(tmp, plane->dev) { | ||
1406 | if (tmp == plane) | ||
1407 | return index; | ||
1408 | |||
1409 | index++; | ||
1410 | } | ||
1411 | |||
1412 | BUG(); | ||
1413 | } | ||
1414 | EXPORT_SYMBOL(drm_plane_index); | ||
1415 | |||
1416 | /** | ||
1417 | * drm_plane_from_index - find the registered plane at an index | 1451 | * drm_plane_from_index - find the registered plane at an index |
1418 | * @dev: DRM device | 1452 | * @dev: DRM device |
1419 | * @idx: index of registered plane to find for | 1453 | * @idx: index of registered plane to find for |
@@ -1425,13 +1459,11 @@ struct drm_plane * | |||
1425 | drm_plane_from_index(struct drm_device *dev, int idx) | 1459 | drm_plane_from_index(struct drm_device *dev, int idx) |
1426 | { | 1460 | { |
1427 | struct drm_plane *plane; | 1461 | struct drm_plane *plane; |
1428 | unsigned int i = 0; | ||
1429 | 1462 | ||
1430 | drm_for_each_plane(plane, dev) { | 1463 | drm_for_each_plane(plane, dev) |
1431 | if (i == idx) | 1464 | if (idx == plane->index) |
1432 | return plane; | 1465 | return plane; |
1433 | i++; | 1466 | |
1434 | } | ||
1435 | return NULL; | 1467 | return NULL; |
1436 | } | 1468 | } |
1437 | EXPORT_SYMBOL(drm_plane_from_index); | 1469 | EXPORT_SYMBOL(drm_plane_from_index); |
@@ -1467,6 +1499,46 @@ void drm_plane_force_disable(struct drm_plane *plane) | |||
1467 | } | 1499 | } |
1468 | EXPORT_SYMBOL(drm_plane_force_disable); | 1500 | EXPORT_SYMBOL(drm_plane_force_disable); |
1469 | 1501 | ||
1502 | int drm_modeset_register_all(struct drm_device *dev) | ||
1503 | { | ||
1504 | int ret; | ||
1505 | |||
1506 | ret = drm_plane_register_all(dev); | ||
1507 | if (ret) | ||
1508 | goto err_plane; | ||
1509 | |||
1510 | ret = drm_crtc_register_all(dev); | ||
1511 | if (ret) | ||
1512 | goto err_crtc; | ||
1513 | |||
1514 | ret = drm_encoder_register_all(dev); | ||
1515 | if (ret) | ||
1516 | goto err_encoder; | ||
1517 | |||
1518 | ret = drm_connector_register_all(dev); | ||
1519 | if (ret) | ||
1520 | goto err_connector; | ||
1521 | |||
1522 | return 0; | ||
1523 | |||
1524 | err_connector: | ||
1525 | drm_encoder_unregister_all(dev); | ||
1526 | err_encoder: | ||
1527 | drm_crtc_unregister_all(dev); | ||
1528 | err_crtc: | ||
1529 | drm_plane_unregister_all(dev); | ||
1530 | err_plane: | ||
1531 | return ret; | ||
1532 | } | ||
1533 | |||
1534 | void drm_modeset_unregister_all(struct drm_device *dev) | ||
1535 | { | ||
1536 | drm_connector_unregister_all(dev); | ||
1537 | drm_encoder_unregister_all(dev); | ||
1538 | drm_crtc_unregister_all(dev); | ||
1539 | drm_plane_unregister_all(dev); | ||
1540 | } | ||
1541 | |||
1470 | static int drm_mode_create_standard_properties(struct drm_device *dev) | 1542 | static int drm_mode_create_standard_properties(struct drm_device *dev) |
1471 | { | 1543 | { |
1472 | struct drm_property *prop; | 1544 | struct drm_property *prop; |
@@ -2975,6 +3047,8 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, | |||
2975 | DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n"); | 3047 | DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n"); |
2976 | return PTR_ERR(fb); | 3048 | return PTR_ERR(fb); |
2977 | } | 3049 | } |
3050 | fb->hot_x = req->hot_x; | ||
3051 | fb->hot_y = req->hot_y; | ||
2978 | } else { | 3052 | } else { |
2979 | fb = NULL; | 3053 | fb = NULL; |
2980 | } | 3054 | } |
@@ -3581,7 +3655,7 @@ int drm_mode_getfb(struct drm_device *dev, | |||
3581 | r->bpp = fb->bits_per_pixel; | 3655 | r->bpp = fb->bits_per_pixel; |
3582 | r->pitch = fb->pitches[0]; | 3656 | r->pitch = fb->pitches[0]; |
3583 | if (fb->funcs->create_handle) { | 3657 | if (fb->funcs->create_handle) { |
3584 | if (file_priv->is_master || capable(CAP_SYS_ADMIN) || | 3658 | if (drm_is_current_master(file_priv) || capable(CAP_SYS_ADMIN) || |
3585 | drm_is_control_client(file_priv)) { | 3659 | drm_is_control_client(file_priv)) { |
3586 | ret = fb->funcs->create_handle(fb, file_priv, | 3660 | ret = fb->funcs->create_handle(fb, file_priv, |
3587 | &r->handle); | 3661 | &r->handle); |
@@ -3738,6 +3812,13 @@ void drm_fb_release(struct drm_file *priv) | |||
3738 | } | 3812 | } |
3739 | } | 3813 | } |
3740 | 3814 | ||
3815 | static bool drm_property_type_valid(struct drm_property *property) | ||
3816 | { | ||
3817 | if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) | ||
3818 | return !(property->flags & DRM_MODE_PROP_LEGACY_TYPE); | ||
3819 | return !!(property->flags & DRM_MODE_PROP_LEGACY_TYPE); | ||
3820 | } | ||
3821 | |||
3741 | /** | 3822 | /** |
3742 | * drm_property_create - create a new property type | 3823 | * drm_property_create - create a new property type |
3743 | * @dev: drm device | 3824 | * @dev: drm device |
@@ -5138,6 +5219,9 @@ EXPORT_SYMBOL(drm_mode_connector_attach_encoder); | |||
5138 | int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, | 5219 | int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, |
5139 | int gamma_size) | 5220 | int gamma_size) |
5140 | { | 5221 | { |
5222 | uint16_t *r_base, *g_base, *b_base; | ||
5223 | int i; | ||
5224 | |||
5141 | crtc->gamma_size = gamma_size; | 5225 | crtc->gamma_size = gamma_size; |
5142 | 5226 | ||
5143 | crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3, | 5227 | crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3, |
@@ -5147,6 +5231,16 @@ int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, | |||
5147 | return -ENOMEM; | 5231 | return -ENOMEM; |
5148 | } | 5232 | } |
5149 | 5233 | ||
5234 | r_base = crtc->gamma_store; | ||
5235 | g_base = r_base + gamma_size; | ||
5236 | b_base = g_base + gamma_size; | ||
5237 | for (i = 0; i < gamma_size; i++) { | ||
5238 | r_base[i] = i << 8; | ||
5239 | g_base[i] = i << 8; | ||
5240 | b_base[i] = i << 8; | ||
5241 | } | ||
5242 | |||
5243 | |||
5150 | return 0; | 5244 | return 0; |
5151 | } | 5245 | } |
5152 | EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); | 5246 | EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); |
@@ -5214,7 +5308,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, | |||
5214 | goto out; | 5308 | goto out; |
5215 | } | 5309 | } |
5216 | 5310 | ||
5217 | crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); | 5311 | ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size); |
5218 | 5312 | ||
5219 | out: | 5313 | out: |
5220 | drm_modeset_unlock_all(dev); | 5314 | drm_modeset_unlock_all(dev); |
@@ -5544,264 +5638,6 @@ int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, | |||
5544 | } | 5638 | } |
5545 | 5639 | ||
5546 | /** | 5640 | /** |
5547 | * drm_fb_get_bpp_depth - get the bpp/depth values for format | ||
5548 | * @format: pixel format (DRM_FORMAT_*) | ||
5549 | * @depth: storage for the depth value | ||
5550 | * @bpp: storage for the bpp value | ||
5551 | * | ||
5552 | * This only supports RGB formats here for compat with code that doesn't use | ||
5553 | * pixel formats directly yet. | ||
5554 | */ | ||
5555 | void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, | ||
5556 | int *bpp) | ||
5557 | { | ||
5558 | switch (format) { | ||
5559 | case DRM_FORMAT_C8: | ||
5560 | case DRM_FORMAT_RGB332: | ||
5561 | case DRM_FORMAT_BGR233: | ||
5562 | *depth = 8; | ||
5563 | *bpp = 8; | ||
5564 | break; | ||
5565 | case DRM_FORMAT_XRGB1555: | ||
5566 | case DRM_FORMAT_XBGR1555: | ||
5567 | case DRM_FORMAT_RGBX5551: | ||
5568 | case DRM_FORMAT_BGRX5551: | ||
5569 | case DRM_FORMAT_ARGB1555: | ||
5570 | case DRM_FORMAT_ABGR1555: | ||
5571 | case DRM_FORMAT_RGBA5551: | ||
5572 | case DRM_FORMAT_BGRA5551: | ||
5573 | *depth = 15; | ||
5574 | *bpp = 16; | ||
5575 | break; | ||
5576 | case DRM_FORMAT_RGB565: | ||
5577 | case DRM_FORMAT_BGR565: | ||
5578 | *depth = 16; | ||
5579 | *bpp = 16; | ||
5580 | break; | ||
5581 | case DRM_FORMAT_RGB888: | ||
5582 | case DRM_FORMAT_BGR888: | ||
5583 | *depth = 24; | ||
5584 | *bpp = 24; | ||
5585 | break; | ||
5586 | case DRM_FORMAT_XRGB8888: | ||
5587 | case DRM_FORMAT_XBGR8888: | ||
5588 | case DRM_FORMAT_RGBX8888: | ||
5589 | case DRM_FORMAT_BGRX8888: | ||
5590 | *depth = 24; | ||
5591 | *bpp = 32; | ||
5592 | break; | ||
5593 | case DRM_FORMAT_XRGB2101010: | ||
5594 | case DRM_FORMAT_XBGR2101010: | ||
5595 | case DRM_FORMAT_RGBX1010102: | ||
5596 | case DRM_FORMAT_BGRX1010102: | ||
5597 | case DRM_FORMAT_ARGB2101010: | ||
5598 | case DRM_FORMAT_ABGR2101010: | ||
5599 | case DRM_FORMAT_RGBA1010102: | ||
5600 | case DRM_FORMAT_BGRA1010102: | ||
5601 | *depth = 30; | ||
5602 | *bpp = 32; | ||
5603 | break; | ||
5604 | case DRM_FORMAT_ARGB8888: | ||
5605 | case DRM_FORMAT_ABGR8888: | ||
5606 | case DRM_FORMAT_RGBA8888: | ||
5607 | case DRM_FORMAT_BGRA8888: | ||
5608 | *depth = 32; | ||
5609 | *bpp = 32; | ||
5610 | break; | ||
5611 | default: | ||
5612 | DRM_DEBUG_KMS("unsupported pixel format %s\n", | ||
5613 | drm_get_format_name(format)); | ||
5614 | *depth = 0; | ||
5615 | *bpp = 0; | ||
5616 | break; | ||
5617 | } | ||
5618 | } | ||
5619 | EXPORT_SYMBOL(drm_fb_get_bpp_depth); | ||
5620 | |||
5621 | /** | ||
5622 | * drm_format_num_planes - get the number of planes for format | ||
5623 | * @format: pixel format (DRM_FORMAT_*) | ||
5624 | * | ||
5625 | * Returns: | ||
5626 | * The number of planes used by the specified pixel format. | ||
5627 | */ | ||
5628 | int drm_format_num_planes(uint32_t format) | ||
5629 | { | ||
5630 | switch (format) { | ||
5631 | case DRM_FORMAT_YUV410: | ||
5632 | case DRM_FORMAT_YVU410: | ||
5633 | case DRM_FORMAT_YUV411: | ||
5634 | case DRM_FORMAT_YVU411: | ||
5635 | case DRM_FORMAT_YUV420: | ||
5636 | case DRM_FORMAT_YVU420: | ||
5637 | case DRM_FORMAT_YUV422: | ||
5638 | case DRM_FORMAT_YVU422: | ||
5639 | case DRM_FORMAT_YUV444: | ||
5640 | case DRM_FORMAT_YVU444: | ||
5641 | return 3; | ||
5642 | case DRM_FORMAT_NV12: | ||
5643 | case DRM_FORMAT_NV21: | ||
5644 | case DRM_FORMAT_NV16: | ||
5645 | case DRM_FORMAT_NV61: | ||
5646 | case DRM_FORMAT_NV24: | ||
5647 | case DRM_FORMAT_NV42: | ||
5648 | return 2; | ||
5649 | default: | ||
5650 | return 1; | ||
5651 | } | ||
5652 | } | ||
5653 | EXPORT_SYMBOL(drm_format_num_planes); | ||
5654 | |||
5655 | /** | ||
5656 | * drm_format_plane_cpp - determine the bytes per pixel value | ||
5657 | * @format: pixel format (DRM_FORMAT_*) | ||
5658 | * @plane: plane index | ||
5659 | * | ||
5660 | * Returns: | ||
5661 | * The bytes per pixel value for the specified plane. | ||
5662 | */ | ||
5663 | int drm_format_plane_cpp(uint32_t format, int plane) | ||
5664 | { | ||
5665 | unsigned int depth; | ||
5666 | int bpp; | ||
5667 | |||
5668 | if (plane >= drm_format_num_planes(format)) | ||
5669 | return 0; | ||
5670 | |||
5671 | switch (format) { | ||
5672 | case DRM_FORMAT_YUYV: | ||
5673 | case DRM_FORMAT_YVYU: | ||
5674 | case DRM_FORMAT_UYVY: | ||
5675 | case DRM_FORMAT_VYUY: | ||
5676 | return 2; | ||
5677 | case DRM_FORMAT_NV12: | ||
5678 | case DRM_FORMAT_NV21: | ||
5679 | case DRM_FORMAT_NV16: | ||
5680 | case DRM_FORMAT_NV61: | ||
5681 | case DRM_FORMAT_NV24: | ||
5682 | case DRM_FORMAT_NV42: | ||
5683 | return plane ? 2 : 1; | ||
5684 | case DRM_FORMAT_YUV410: | ||
5685 | case DRM_FORMAT_YVU410: | ||
5686 | case DRM_FORMAT_YUV411: | ||
5687 | case DRM_FORMAT_YVU411: | ||
5688 | case DRM_FORMAT_YUV420: | ||
5689 | case DRM_FORMAT_YVU420: | ||
5690 | case DRM_FORMAT_YUV422: | ||
5691 | case DRM_FORMAT_YVU422: | ||
5692 | case DRM_FORMAT_YUV444: | ||
5693 | case DRM_FORMAT_YVU444: | ||
5694 | return 1; | ||
5695 | default: | ||
5696 | drm_fb_get_bpp_depth(format, &depth, &bpp); | ||
5697 | return bpp >> 3; | ||
5698 | } | ||
5699 | } | ||
5700 | EXPORT_SYMBOL(drm_format_plane_cpp); | ||
5701 | |||
5702 | /** | ||
5703 | * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor | ||
5704 | * @format: pixel format (DRM_FORMAT_*) | ||
5705 | * | ||
5706 | * Returns: | ||
5707 | * The horizontal chroma subsampling factor for the | ||
5708 | * specified pixel format. | ||
5709 | */ | ||
5710 | int drm_format_horz_chroma_subsampling(uint32_t format) | ||
5711 | { | ||
5712 | switch (format) { | ||
5713 | case DRM_FORMAT_YUV411: | ||
5714 | case DRM_FORMAT_YVU411: | ||
5715 | case DRM_FORMAT_YUV410: | ||
5716 | case DRM_FORMAT_YVU410: | ||
5717 | return 4; | ||
5718 | case DRM_FORMAT_YUYV: | ||
5719 | case DRM_FORMAT_YVYU: | ||
5720 | case DRM_FORMAT_UYVY: | ||
5721 | case DRM_FORMAT_VYUY: | ||
5722 | case DRM_FORMAT_NV12: | ||
5723 | case DRM_FORMAT_NV21: | ||
5724 | case DRM_FORMAT_NV16: | ||
5725 | case DRM_FORMAT_NV61: | ||
5726 | case DRM_FORMAT_YUV422: | ||
5727 | case DRM_FORMAT_YVU422: | ||
5728 | case DRM_FORMAT_YUV420: | ||
5729 | case DRM_FORMAT_YVU420: | ||
5730 | return 2; | ||
5731 | default: | ||
5732 | return 1; | ||
5733 | } | ||
5734 | } | ||
5735 | EXPORT_SYMBOL(drm_format_horz_chroma_subsampling); | ||
5736 | |||
5737 | /** | ||
5738 | * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor | ||
5739 | * @format: pixel format (DRM_FORMAT_*) | ||
5740 | * | ||
5741 | * Returns: | ||
5742 | * The vertical chroma subsampling factor for the | ||
5743 | * specified pixel format. | ||
5744 | */ | ||
5745 | int drm_format_vert_chroma_subsampling(uint32_t format) | ||
5746 | { | ||
5747 | switch (format) { | ||
5748 | case DRM_FORMAT_YUV410: | ||
5749 | case DRM_FORMAT_YVU410: | ||
5750 | return 4; | ||
5751 | case DRM_FORMAT_YUV420: | ||
5752 | case DRM_FORMAT_YVU420: | ||
5753 | case DRM_FORMAT_NV12: | ||
5754 | case DRM_FORMAT_NV21: | ||
5755 | return 2; | ||
5756 | default: | ||
5757 | return 1; | ||
5758 | } | ||
5759 | } | ||
5760 | EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); | ||
5761 | |||
5762 | /** | ||
5763 | * drm_format_plane_width - width of the plane given the first plane | ||
5764 | * @width: width of the first plane | ||
5765 | * @format: pixel format | ||
5766 | * @plane: plane index | ||
5767 | * | ||
5768 | * Returns: | ||
5769 | * The width of @plane, given that the width of the first plane is @width. | ||
5770 | */ | ||
5771 | int drm_format_plane_width(int width, uint32_t format, int plane) | ||
5772 | { | ||
5773 | if (plane >= drm_format_num_planes(format)) | ||
5774 | return 0; | ||
5775 | |||
5776 | if (plane == 0) | ||
5777 | return width; | ||
5778 | |||
5779 | return width / drm_format_horz_chroma_subsampling(format); | ||
5780 | } | ||
5781 | EXPORT_SYMBOL(drm_format_plane_width); | ||
5782 | |||
5783 | /** | ||
5784 | * drm_format_plane_height - height of the plane given the first plane | ||
5785 | * @height: height of the first plane | ||
5786 | * @format: pixel format | ||
5787 | * @plane: plane index | ||
5788 | * | ||
5789 | * Returns: | ||
5790 | * The height of @plane, given that the height of the first plane is @height. | ||
5791 | */ | ||
5792 | int drm_format_plane_height(int height, uint32_t format, int plane) | ||
5793 | { | ||
5794 | if (plane >= drm_format_num_planes(format)) | ||
5795 | return 0; | ||
5796 | |||
5797 | if (plane == 0) | ||
5798 | return height; | ||
5799 | |||
5800 | return height / drm_format_vert_chroma_subsampling(format); | ||
5801 | } | ||
5802 | EXPORT_SYMBOL(drm_format_plane_height); | ||
5803 | |||
5804 | /** | ||
5805 | * drm_rotation_simplify() - Try to simplify the rotation | 5641 | * drm_rotation_simplify() - Try to simplify the rotation |
5806 | * @rotation: Rotation to be simplified | 5642 | * @rotation: Rotation to be simplified |
5807 | * @supported_rotations: Supported rotations | 5643 | * @supported_rotations: Supported rotations |
@@ -6064,3 +5900,48 @@ struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, | |||
6064 | return tg; | 5900 | return tg; |
6065 | } | 5901 | } |
6066 | EXPORT_SYMBOL(drm_mode_create_tile_group); | 5902 | EXPORT_SYMBOL(drm_mode_create_tile_group); |
5903 | |||
5904 | /** | ||
5905 | * drm_crtc_enable_color_mgmt - enable color management properties | ||
5906 | * @crtc: DRM CRTC | ||
5907 | * @degamma_lut_size: the size of the degamma lut (before CSC) | ||
5908 | * @has_ctm: whether to attach ctm_property for CSC matrix | ||
5909 | * @gamma_lut_size: the size of the gamma lut (after CSC) | ||
5910 | * | ||
5911 | * This function lets the driver enable the color correction | ||
5912 | * properties on a CRTC. This includes 3 degamma, csc and gamma | ||
5913 | * properties that userspace can set and 2 size properties to inform | ||
5914 | * the userspace of the lut sizes. Each of the properties are | ||
5915 | * optional. The gamma and degamma properties are only attached if | ||
5916 | * their size is not 0 and ctm_property is only attached if has_ctm is | ||
5917 | * true. | ||
5918 | */ | ||
5919 | void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc, | ||
5920 | uint degamma_lut_size, | ||
5921 | bool has_ctm, | ||
5922 | uint gamma_lut_size) | ||
5923 | { | ||
5924 | struct drm_device *dev = crtc->dev; | ||
5925 | struct drm_mode_config *config = &dev->mode_config; | ||
5926 | |||
5927 | if (degamma_lut_size) { | ||
5928 | drm_object_attach_property(&crtc->base, | ||
5929 | config->degamma_lut_property, 0); | ||
5930 | drm_object_attach_property(&crtc->base, | ||
5931 | config->degamma_lut_size_property, | ||
5932 | degamma_lut_size); | ||
5933 | } | ||
5934 | |||
5935 | if (has_ctm) | ||
5936 | drm_object_attach_property(&crtc->base, | ||
5937 | config->ctm_property, 0); | ||
5938 | |||
5939 | if (gamma_lut_size) { | ||
5940 | drm_object_attach_property(&crtc->base, | ||
5941 | config->gamma_lut_property, 0); | ||
5942 | drm_object_attach_property(&crtc->base, | ||
5943 | config->gamma_lut_size_property, | ||
5944 | gamma_lut_size); | ||
5945 | } | ||
5946 | } | ||
5947 | EXPORT_SYMBOL(drm_crtc_enable_color_mgmt); | ||