| .. | .. |
|---|
| 20 | 20 | * OF THIS SOFTWARE. |
|---|
| 21 | 21 | */ |
|---|
| 22 | 22 | |
|---|
| 23 | | -#include <drm/drmP.h> |
|---|
| 24 | 23 | #include <drm/drm_connector.h> |
|---|
| 25 | 24 | #include <drm/drm_edid.h> |
|---|
| 26 | 25 | #include <drm/drm_encoder.h> |
|---|
| 27 | 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> |
|---|
| 28 | 33 | |
|---|
| 29 | 34 | #include "drm_crtc_internal.h" |
|---|
| 30 | 35 | #include "drm_internal.h" |
|---|
| .. | .. |
|---|
| 33 | 38 | * DOC: overview |
|---|
| 34 | 39 | * |
|---|
| 35 | 40 | * In DRM connectors are the general abstraction for display sinks, and include |
|---|
| 36 | | - * als fixed panels or anything else that can display pixels in some form. As |
|---|
| 41 | + * also fixed panels or anything else that can display pixels in some form. As |
|---|
| 37 | 42 | * opposed to all other KMS objects representing hardware (like CRTC, encoder or |
|---|
| 38 | 43 | * plane abstractions) connectors can be hotplugged and unplugged at runtime. |
|---|
| 39 | 44 | * Hence they are reference-counted using drm_connector_get() and |
|---|
| .. | .. |
|---|
| 88 | 93 | { DRM_MODE_CONNECTOR_DSI, "DSI" }, |
|---|
| 89 | 94 | { DRM_MODE_CONNECTOR_DPI, "DPI" }, |
|---|
| 90 | 95 | { DRM_MODE_CONNECTOR_WRITEBACK, "Writeback" }, |
|---|
| 96 | + { DRM_MODE_CONNECTOR_SPI, "SPI" }, |
|---|
| 91 | 97 | }; |
|---|
| 92 | | - |
|---|
| 93 | | -DRM_ENUM_NAME_FN(drm_get_connector_name, drm_connector_enum_list) |
|---|
| 94 | | -EXPORT_SYMBOL(drm_get_connector_name); |
|---|
| 95 | 98 | |
|---|
| 96 | 99 | void drm_connector_ida_init(void) |
|---|
| 97 | 100 | { |
|---|
| .. | .. |
|---|
| 110 | 113 | } |
|---|
| 111 | 114 | |
|---|
| 112 | 115 | /** |
|---|
| 116 | + * drm_get_connector_type_name - return a string for connector type |
|---|
| 117 | + * @type: The connector type (DRM_MODE_CONNECTOR_*) |
|---|
| 118 | + * |
|---|
| 119 | + * Returns: the name of the connector type, or NULL if the type is not valid. |
|---|
| 120 | + */ |
|---|
| 121 | +const 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 | +} |
|---|
| 128 | +EXPORT_SYMBOL(drm_get_connector_type_name); |
|---|
| 129 | + |
|---|
| 130 | +/** |
|---|
| 113 | 131 | * drm_connector_get_cmdline_mode - reads the user's cmdline mode |
|---|
| 114 | | - * @connector: connector to quwery |
|---|
| 132 | + * @connector: connector to query |
|---|
| 115 | 133 | * |
|---|
| 116 | 134 | * The kernel supports per-connector configuration of its consoles through |
|---|
| 117 | 135 | * use of the video= parameter. This function parses that option and |
|---|
| .. | .. |
|---|
| 138 | 156 | connector->force = mode->force; |
|---|
| 139 | 157 | } |
|---|
| 140 | 158 | |
|---|
| 141 | | - DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", |
|---|
| 142 | | - connector->name, |
|---|
| 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, |
|---|
| 143 | 168 | mode->xres, mode->yres, |
|---|
| 144 | 169 | mode->refresh_specified ? mode->refresh : 60, |
|---|
| 145 | 170 | mode->rb ? " reduced blanking" : "", |
|---|
| .. | .. |
|---|
| 244 | 269 | INIT_LIST_HEAD(&connector->modes); |
|---|
| 245 | 270 | mutex_init(&connector->mutex); |
|---|
| 246 | 271 | connector->edid_blob_ptr = NULL; |
|---|
| 272 | + connector->epoch_counter = 0; |
|---|
| 273 | + connector->tile_blob_ptr = NULL; |
|---|
| 247 | 274 | connector->status = connector_status_unknown; |
|---|
| 248 | 275 | connector->display_info.panel_orientation = |
|---|
| 249 | 276 | DRM_MODE_PANEL_ORIENTATION_UNKNOWN; |
|---|
| .. | .. |
|---|
| 271 | 298 | drm_object_attach_property(&connector->base, |
|---|
| 272 | 299 | config->non_desktop_property, |
|---|
| 273 | 300 | 0); |
|---|
| 301 | + drm_object_attach_property(&connector->base, |
|---|
| 302 | + config->tile_property, |
|---|
| 303 | + 0); |
|---|
| 274 | 304 | |
|---|
| 275 | 305 | if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { |
|---|
| 276 | 306 | drm_object_attach_property(&connector->base, config->prop_crtc_id, 0); |
|---|
| .. | .. |
|---|
| 290 | 320 | return ret; |
|---|
| 291 | 321 | } |
|---|
| 292 | 322 | EXPORT_SYMBOL(drm_connector_init); |
|---|
| 323 | + |
|---|
| 324 | +/** |
|---|
| 325 | + * drm_connector_init_with_ddc - Init a preallocated connector |
|---|
| 326 | + * @dev: DRM device |
|---|
| 327 | + * @connector: the connector to init |
|---|
| 328 | + * @funcs: callbacks for this connector |
|---|
| 329 | + * @connector_type: user visible type of the connector |
|---|
| 330 | + * @ddc: pointer to the associated ddc adapter |
|---|
| 331 | + * |
|---|
| 332 | + * Initialises a preallocated connector. Connectors should be |
|---|
| 333 | + * subclassed as part of driver connector objects. |
|---|
| 334 | + * |
|---|
| 335 | + * Ensures that the ddc field of the connector is correctly set. |
|---|
| 336 | + * |
|---|
| 337 | + * Returns: |
|---|
| 338 | + * Zero on success, error code on failure. |
|---|
| 339 | + */ |
|---|
| 340 | +int 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 | + /* provide ddc symlink in sysfs */ |
|---|
| 353 | + connector->ddc = ddc; |
|---|
| 354 | + |
|---|
| 355 | + return ret; |
|---|
| 356 | +} |
|---|
| 357 | +EXPORT_SYMBOL(drm_connector_init_with_ddc); |
|---|
| 293 | 358 | |
|---|
| 294 | 359 | /** |
|---|
| 295 | 360 | * drm_connector_attach_edid_property - attach edid property. |
|---|
| .. | .. |
|---|
| 324 | 389 | int drm_connector_attach_encoder(struct drm_connector *connector, |
|---|
| 325 | 390 | struct drm_encoder *encoder) |
|---|
| 326 | 391 | { |
|---|
| 327 | | - int i; |
|---|
| 328 | | - |
|---|
| 329 | 392 | /* |
|---|
| 330 | 393 | * In the past, drivers have attempted to model the static association |
|---|
| 331 | 394 | * of connector to encoder in simple connector/encoder devices using a |
|---|
| .. | .. |
|---|
| 340 | 403 | if (WARN_ON(connector->encoder)) |
|---|
| 341 | 404 | return -EINVAL; |
|---|
| 342 | 405 | |
|---|
| 343 | | - for (i = 0; i < ARRAY_SIZE(connector->encoder_ids); i++) { |
|---|
| 344 | | - if (connector->encoder_ids[i] == 0) { |
|---|
| 345 | | - connector->encoder_ids[i] = encoder->base.id; |
|---|
| 346 | | - return 0; |
|---|
| 347 | | - } |
|---|
| 348 | | - } |
|---|
| 349 | | - return -ENOMEM; |
|---|
| 406 | + connector->possible_encoders |= drm_encoder_mask(encoder); |
|---|
| 407 | + |
|---|
| 408 | + return 0; |
|---|
| 350 | 409 | } |
|---|
| 351 | 410 | EXPORT_SYMBOL(drm_connector_attach_encoder); |
|---|
| 352 | 411 | |
|---|
| 353 | 412 | /** |
|---|
| 354 | | - * drm_connector_has_possible_encoder - check if the connector and encoder are assosicated with each other |
|---|
| 413 | + * drm_connector_has_possible_encoder - check if the connector and encoder are |
|---|
| 414 | + * associated with each other |
|---|
| 355 | 415 | * @connector: the connector |
|---|
| 356 | 416 | * @encoder: the encoder |
|---|
| 357 | 417 | * |
|---|
| .. | .. |
|---|
| 361 | 421 | bool drm_connector_has_possible_encoder(struct drm_connector *connector, |
|---|
| 362 | 422 | struct drm_encoder *encoder) |
|---|
| 363 | 423 | { |
|---|
| 364 | | - struct drm_encoder *enc; |
|---|
| 365 | | - int i; |
|---|
| 366 | | - |
|---|
| 367 | | - drm_connector_for_each_possible_encoder(connector, enc, i) { |
|---|
| 368 | | - if (enc == encoder) |
|---|
| 369 | | - return true; |
|---|
| 370 | | - } |
|---|
| 371 | | - |
|---|
| 372 | | - return false; |
|---|
| 424 | + return connector->possible_encoders & drm_encoder_mask(encoder); |
|---|
| 373 | 425 | } |
|---|
| 374 | 426 | EXPORT_SYMBOL(drm_connector_has_possible_encoder); |
|---|
| 375 | 427 | |
|---|
| .. | .. |
|---|
| 439 | 491 | * drm_connector_register - register a connector |
|---|
| 440 | 492 | * @connector: the connector to register |
|---|
| 441 | 493 | * |
|---|
| 442 | | - * Register userspace interfaces for a connector |
|---|
| 494 | + * Register userspace interfaces for a connector. Only call this for connectors |
|---|
| 495 | + * which can be hotplugged after drm_dev_register() has been called already, |
|---|
| 496 | + * e.g. DP MST connectors. All other connectors will be registered automatically |
|---|
| 497 | + * when calling drm_dev_register(). |
|---|
| 443 | 498 | * |
|---|
| 444 | 499 | * Returns: |
|---|
| 445 | 500 | * Zero on success, error code on failure. |
|---|
| .. | .. |
|---|
| 459 | 514 | if (ret) |
|---|
| 460 | 515 | goto unlock; |
|---|
| 461 | 516 | |
|---|
| 462 | | - ret = drm_debugfs_connector_add(connector); |
|---|
| 463 | | - if (ret) { |
|---|
| 464 | | - goto err_sysfs; |
|---|
| 465 | | - } |
|---|
| 517 | + drm_debugfs_connector_add(connector); |
|---|
| 466 | 518 | |
|---|
| 467 | 519 | if (connector->funcs->late_register) { |
|---|
| 468 | 520 | ret = connector->funcs->late_register(connector); |
|---|
| .. | .. |
|---|
| 473 | 525 | drm_mode_object_register(connector->dev, &connector->base); |
|---|
| 474 | 526 | |
|---|
| 475 | 527 | connector->registration_state = DRM_CONNECTOR_REGISTERED; |
|---|
| 528 | + |
|---|
| 529 | + /* Let userspace know we have a new connector */ |
|---|
| 530 | + drm_sysfs_hotplug_event(connector->dev); |
|---|
| 531 | + |
|---|
| 476 | 532 | goto unlock; |
|---|
| 477 | 533 | |
|---|
| 478 | 534 | err_debugfs: |
|---|
| 479 | 535 | drm_debugfs_connector_remove(connector); |
|---|
| 480 | | -err_sysfs: |
|---|
| 481 | 536 | drm_sysfs_connector_remove(connector); |
|---|
| 482 | 537 | unlock: |
|---|
| 483 | 538 | mutex_unlock(&connector->mutex); |
|---|
| .. | .. |
|---|
| 489 | 544 | * drm_connector_unregister - unregister a connector |
|---|
| 490 | 545 | * @connector: the connector to unregister |
|---|
| 491 | 546 | * |
|---|
| 492 | | - * Unregister userspace interfaces for a connector |
|---|
| 547 | + * Unregister userspace interfaces for a connector. Only call this for |
|---|
| 548 | + * connectors which have registered explicitly by calling drm_dev_register(), |
|---|
| 549 | + * since connectors are unregistered automatically when drm_dev_unregister() is |
|---|
| 550 | + * called. |
|---|
| 493 | 551 | */ |
|---|
| 494 | 552 | void drm_connector_unregister(struct drm_connector *connector) |
|---|
| 495 | 553 | { |
|---|
| .. | .. |
|---|
| 682 | 740 | __drm_connector_put_safe(iter->conn); |
|---|
| 683 | 741 | spin_unlock_irqrestore(&config->connector_list_lock, flags); |
|---|
| 684 | 742 | } |
|---|
| 685 | | - lock_release(&connector_list_iter_dep_map, 0, _RET_IP_); |
|---|
| 743 | + lock_release(&connector_list_iter_dep_map, _RET_IP_); |
|---|
| 686 | 744 | } |
|---|
| 687 | 745 | EXPORT_SYMBOL(drm_connector_list_iter_end); |
|---|
| 688 | 746 | |
|---|
| .. | .. |
|---|
| 792 | 850 | DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) |
|---|
| 793 | 851 | |
|---|
| 794 | 852 | static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = { |
|---|
| 795 | | - { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ |
|---|
| 853 | + { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */ |
|---|
| 796 | 854 | { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ |
|---|
| 797 | 855 | { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ |
|---|
| 798 | 856 | }; |
|---|
| .. | .. |
|---|
| 809 | 867 | DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) |
|---|
| 810 | 868 | |
|---|
| 811 | 869 | static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { |
|---|
| 812 | | - { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ |
|---|
| 870 | + { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */ |
|---|
| 813 | 871 | { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ |
|---|
| 814 | 872 | { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ |
|---|
| 815 | 873 | { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ |
|---|
| .. | .. |
|---|
| 818 | 876 | DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, |
|---|
| 819 | 877 | drm_tv_subconnector_enum_list) |
|---|
| 820 | 878 | |
|---|
| 821 | | -static struct drm_prop_enum_list drm_cp_enum_list[] = { |
|---|
| 822 | | - { DRM_MODE_CONTENT_PROTECTION_UNDESIRED, "Undesired" }, |
|---|
| 823 | | - { DRM_MODE_CONTENT_PROTECTION_DESIRED, "Desired" }, |
|---|
| 824 | | - { DRM_MODE_CONTENT_PROTECTION_ENABLED, "Enabled" }, |
|---|
| 879 | +static const struct drm_prop_enum_list drm_dp_subconnector_enum_list[] = { |
|---|
| 880 | + { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */ |
|---|
| 881 | + { DRM_MODE_SUBCONNECTOR_VGA, "VGA" }, /* DP */ |
|---|
| 882 | + { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DP */ |
|---|
| 883 | + { DRM_MODE_SUBCONNECTOR_HDMIA, "HDMI" }, /* DP */ |
|---|
| 884 | + { DRM_MODE_SUBCONNECTOR_DisplayPort, "DP" }, /* DP */ |
|---|
| 885 | + { DRM_MODE_SUBCONNECTOR_Wireless, "Wireless" }, /* DP */ |
|---|
| 886 | + { DRM_MODE_SUBCONNECTOR_Native, "Native" }, /* DP */ |
|---|
| 825 | 887 | }; |
|---|
| 826 | | -DRM_ENUM_NAME_FN(drm_get_content_protection_name, drm_cp_enum_list) |
|---|
| 888 | + |
|---|
| 889 | +DRM_ENUM_NAME_FN(drm_get_dp_subconnector_name, |
|---|
| 890 | + drm_dp_subconnector_enum_list) |
|---|
| 827 | 891 | |
|---|
| 828 | 892 | static const struct drm_prop_enum_list hdmi_colorspaces[] = { |
|---|
| 829 | 893 | /* For Default case, driver will set the colorspace */ |
|---|
| .. | .. |
|---|
| 852 | 916 | { DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER, "DCI-P3_RGB_Theater" }, |
|---|
| 853 | 917 | }; |
|---|
| 854 | 918 | |
|---|
| 919 | +/* |
|---|
| 920 | + * As per DP 1.4a spec, 2.2.5.7.5 VSC SDP Payload for Pixel Encoding/Colorimetry |
|---|
| 921 | + * Format Table 2-120 |
|---|
| 922 | + */ |
|---|
| 855 | 923 | static const struct drm_prop_enum_list dp_colorspaces[] = { |
|---|
| 856 | 924 | /* For Default case, driver will set the colorspace */ |
|---|
| 857 | 925 | { DRM_MODE_COLORIMETRY_DEFAULT, "Default" }, |
|---|
| 926 | + { DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED, "RGB_Wide_Gamut_Fixed_Point" }, |
|---|
| 927 | + /* Colorimetry based on scRGB (IEC 61966-2-2) */ |
|---|
| 928 | + { DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT, "RGB_Wide_Gamut_Floating_Point" }, |
|---|
| 929 | + /* Colorimetry based on IEC 61966-2-5 */ |
|---|
| 930 | + { DRM_MODE_COLORIMETRY_OPRGB, "opRGB" }, |
|---|
| 931 | + /* Colorimetry based on SMPTE RP 431-2 */ |
|---|
| 932 | + { DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65, "DCI-P3_RGB_D65" }, |
|---|
| 933 | + /* Colorimetry based on ITU-R BT.2020 */ |
|---|
| 934 | + { DRM_MODE_COLORIMETRY_BT2020_RGB, "BT2020_RGB" }, |
|---|
| 935 | + { DRM_MODE_COLORIMETRY_BT601_YCC, "BT601_YCC" }, |
|---|
| 936 | + { DRM_MODE_COLORIMETRY_BT709_YCC, "BT709_YCC" }, |
|---|
| 858 | 937 | /* Standard Definition Colorimetry based on IEC 61966-2-4 */ |
|---|
| 859 | 938 | { DRM_MODE_COLORIMETRY_XVYCC_601, "XVYCC_601" }, |
|---|
| 860 | 939 | /* High Definition Colorimetry based on IEC 61966-2-4 */ |
|---|
| 861 | 940 | { DRM_MODE_COLORIMETRY_XVYCC_709, "XVYCC_709" }, |
|---|
| 862 | | - /* Colorimetry based on IEC 61966-2-5 */ |
|---|
| 863 | | - { DRM_MODE_COLORIMETRY_OPRGB, "opRGB" }, |
|---|
| 864 | | - { DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65, "DCI-P3_RGB_D65" }, |
|---|
| 865 | | - /* DP MSA Colorimetry */ |
|---|
| 866 | | - { DRM_MODE_DP_COLORIMETRY_BT601_YCC, "YCBCR_ITU_601" }, |
|---|
| 867 | | - { DRM_MODE_DP_COLORIMETRY_BT709_YCC, "YCBCR_ITU_709" }, |
|---|
| 868 | | - { DRM_MODE_DP_COLORIMETRY_SRGB, "sRGB" }, |
|---|
| 869 | | - { DRM_MODE_DP_COLORIMETRY_RGB_WIDE_GAMUT, "RGB Wide Gamut" }, |
|---|
| 870 | | - { DRM_MODE_DP_COLORIMETRY_SCRGB, "scRGB" }, |
|---|
| 941 | + /* Colorimetry based on IEC 61966-2-1/Amendment 1 */ |
|---|
| 942 | + { DRM_MODE_COLORIMETRY_SYCC_601, "SYCC_601" }, |
|---|
| 943 | + /* Colorimetry based on IEC 61966-2-5 [33] */ |
|---|
| 944 | + { DRM_MODE_COLORIMETRY_OPYCC_601, "opYCC_601" }, |
|---|
| 871 | 945 | /* Colorimetry based on ITU-R BT.2020 */ |
|---|
| 872 | | - { DRM_MODE_COLORIMETRY_BT2020_RGB, "BT2020_RGB" }, |
|---|
| 946 | + { DRM_MODE_COLORIMETRY_BT2020_CYCC, "BT2020_CYCC" }, |
|---|
| 873 | 947 | /* Colorimetry based on ITU-R BT.2020 */ |
|---|
| 874 | 948 | { DRM_MODE_COLORIMETRY_BT2020_YCC, "BT2020_YCC" }, |
|---|
| 875 | 949 | }; |
|---|
| .. | .. |
|---|
| 893 | 967 | * connector is linked to. Drivers should never set this property directly, |
|---|
| 894 | 968 | * it is handled by the DRM core by calling the &drm_connector_funcs.dpms |
|---|
| 895 | 969 | * callback. For atomic drivers the remapping to the "ACTIVE" property is |
|---|
| 896 | | - * implemented in the DRM core. This is the only standard connector |
|---|
| 897 | | - * property that userspace can change. |
|---|
| 970 | + * implemented in the DRM core. |
|---|
| 898 | 971 | * |
|---|
| 899 | 972 | * Note that this property cannot be set through the MODE_ATOMIC ioctl, |
|---|
| 900 | 973 | * userspace must use "ACTIVE" on the CRTC instead. |
|---|
| .. | .. |
|---|
| 931 | 1004 | * DP MST sinks), or high-res integrated panels (like dual-link DSI) which |
|---|
| 932 | 1005 | * are not gen-locked. Note that for tiled panels which are genlocked, like |
|---|
| 933 | 1006 | * dual-link LVDS or dual-link DSI, the driver should try to not expose the |
|---|
| 934 | | - * tiling and virtualize both &drm_crtc and &drm_plane if needed. Drivers |
|---|
| 1007 | + * tiling and virtualise both &drm_crtc and &drm_plane if needed. Drivers |
|---|
| 935 | 1008 | * should update this value using drm_connector_set_tile_property(). |
|---|
| 936 | 1009 | * Userspace cannot change this property. |
|---|
| 937 | 1010 | * link-status: |
|---|
| .. | .. |
|---|
| 940 | 1013 | * after modeset, the kernel driver may set this to "BAD" and issue a |
|---|
| 941 | 1014 | * hotplug uevent. Drivers should update this value using |
|---|
| 942 | 1015 | * drm_connector_set_link_status_property(). |
|---|
| 1016 | + * |
|---|
| 1017 | + * When user-space receives the hotplug uevent and detects a "BAD" |
|---|
| 1018 | + * link-status, the sink doesn't receive pixels anymore (e.g. the screen |
|---|
| 1019 | + * becomes completely black). The list of available modes may have |
|---|
| 1020 | + * changed. User-space is expected to pick a new mode if the current one |
|---|
| 1021 | + * has disappeared and perform a new modeset with link-status set to |
|---|
| 1022 | + * "GOOD" to re-enable the connector. |
|---|
| 1023 | + * |
|---|
| 1024 | + * If multiple connectors share the same CRTC and one of them gets a "BAD" |
|---|
| 1025 | + * link-status, the other are unaffected (ie. the sinks still continue to |
|---|
| 1026 | + * receive pixels). |
|---|
| 1027 | + * |
|---|
| 1028 | + * When user-space performs an atomic commit on a connector with a "BAD" |
|---|
| 1029 | + * link-status without resetting the property to "GOOD", the sink may |
|---|
| 1030 | + * still not receive pixels. When user-space performs an atomic commit |
|---|
| 1031 | + * which resets the link-status property to "GOOD" without the |
|---|
| 1032 | + * ALLOW_MODESET flag set, it might fail because a modeset is required. |
|---|
| 1033 | + * |
|---|
| 1034 | + * User-space can only change link-status to "GOOD", changing it to "BAD" |
|---|
| 1035 | + * is a no-op. |
|---|
| 1036 | + * |
|---|
| 1037 | + * For backwards compatibility with non-atomic userspace the kernel |
|---|
| 1038 | + * tries to automatically set the link-status back to "GOOD" in the |
|---|
| 1039 | + * SETCRTC IOCTL. This might fail if the mode is no longer valid, similar |
|---|
| 1040 | + * to how it might fail if a different screen has been connected in the |
|---|
| 1041 | + * interim. |
|---|
| 943 | 1042 | * non_desktop: |
|---|
| 944 | 1043 | * Indicates the output should be ignored for purposes of displaying a |
|---|
| 945 | 1044 | * standard desktop environment or console. This is most likely because |
|---|
| .. | .. |
|---|
| 975 | 1074 | * - If the state is DESIRED, kernel should attempt to re-authenticate the |
|---|
| 976 | 1075 | * link whenever possible. This includes across disable/enable, dpms, |
|---|
| 977 | 1076 | * hotplug, downstream device changes, link status failures, etc.. |
|---|
| 978 | | - * - Userspace is responsible for polling the property to determine when |
|---|
| 979 | | - * the value transitions from ENABLED to DESIRED. This signifies the link |
|---|
| 980 | | - * is no longer protected and userspace should take appropriate action |
|---|
| 981 | | - * (whatever that might be). |
|---|
| 1077 | + * - Kernel sends uevent with the connector id and property id through |
|---|
| 1078 | + * @drm_hdcp_update_content_protection, upon below kernel triggered |
|---|
| 1079 | + * scenarios: |
|---|
| 1080 | + * |
|---|
| 1081 | + * - DESIRED -> ENABLED (authentication success) |
|---|
| 1082 | + * - ENABLED -> DESIRED (termination of authentication) |
|---|
| 1083 | + * - Please note no uevents for userspace triggered property state changes, |
|---|
| 1084 | + * which can't fail such as |
|---|
| 1085 | + * |
|---|
| 1086 | + * - DESIRED/ENABLED -> UNDESIRED |
|---|
| 1087 | + * - UNDESIRED -> DESIRED |
|---|
| 1088 | + * - Userspace is responsible for polling the property or listen to uevents |
|---|
| 1089 | + * to determine when the value transitions from ENABLED to DESIRED. |
|---|
| 1090 | + * This signifies the link is no longer protected and userspace should |
|---|
| 1091 | + * take appropriate action (whatever that might be). |
|---|
| 1092 | + * |
|---|
| 1093 | + * HDCP Content Type: |
|---|
| 1094 | + * This Enum property is used by the userspace to declare the content type |
|---|
| 1095 | + * of the display stream, to kernel. Here display stream stands for any |
|---|
| 1096 | + * display content that userspace intended to display through HDCP |
|---|
| 1097 | + * encryption. |
|---|
| 1098 | + * |
|---|
| 1099 | + * Content Type of a stream is decided by the owner of the stream, as |
|---|
| 1100 | + * "HDCP Type0" or "HDCP Type1". |
|---|
| 1101 | + * |
|---|
| 1102 | + * The value of the property can be one of the below: |
|---|
| 1103 | + * - "HDCP Type0": DRM_MODE_HDCP_CONTENT_TYPE0 = 0 |
|---|
| 1104 | + * - "HDCP Type1": DRM_MODE_HDCP_CONTENT_TYPE1 = 1 |
|---|
| 1105 | + * |
|---|
| 1106 | + * When kernel starts the HDCP authentication (see "Content Protection" |
|---|
| 1107 | + * for details), it uses the content type in "HDCP Content Type" |
|---|
| 1108 | + * for performing the HDCP authentication with the display sink. |
|---|
| 1109 | + * |
|---|
| 1110 | + * Please note in HDCP spec versions, a link can be authenticated with |
|---|
| 1111 | + * HDCP 2.2 for Content Type 0/Content Type 1. Where as a link can be |
|---|
| 1112 | + * authenticated with HDCP1.4 only for Content Type 0(though it is implicit |
|---|
| 1113 | + * in nature. As there is no reference for Content Type in HDCP1.4). |
|---|
| 1114 | + * |
|---|
| 1115 | + * HDCP2.2 authentication protocol itself takes the "Content Type" as a |
|---|
| 1116 | + * parameter, which is a input for the DP HDCP2.2 encryption algo. |
|---|
| 1117 | + * |
|---|
| 1118 | + * In case of Type 0 content protection request, kernel driver can choose |
|---|
| 1119 | + * either of HDCP spec versions 1.4 and 2.2. When HDCP2.2 is used for |
|---|
| 1120 | + * "HDCP Type 0", a HDCP 2.2 capable repeater in the downstream can send |
|---|
| 1121 | + * that content to a HDCP 1.4 authenticated HDCP sink (Type0 link). |
|---|
| 1122 | + * But if the content is classified as "HDCP Type 1", above mentioned |
|---|
| 1123 | + * HDCP 2.2 repeater wont send the content to the HDCP sink as it can't |
|---|
| 1124 | + * authenticate the HDCP1.4 capable sink for "HDCP Type 1". |
|---|
| 1125 | + * |
|---|
| 1126 | + * Please note userspace can be ignorant of the HDCP versions used by the |
|---|
| 1127 | + * kernel driver to achieve the "HDCP Content Type". |
|---|
| 1128 | + * |
|---|
| 1129 | + * At current scenario, classifying a content as Type 1 ensures that the |
|---|
| 1130 | + * content will be displayed only through the HDCP2.2 encrypted link. |
|---|
| 1131 | + * |
|---|
| 1132 | + * Note that the HDCP Content Type property is introduced at HDCP 2.2, and |
|---|
| 1133 | + * defaults to type 0. It is only exposed by drivers supporting HDCP 2.2 |
|---|
| 1134 | + * (hence supporting Type 0 and Type 1). Based on how next versions of |
|---|
| 1135 | + * HDCP specs are defined content Type could be used for higher versions |
|---|
| 1136 | + * too. |
|---|
| 1137 | + * |
|---|
| 1138 | + * If content type is changed when "Content Protection" is not UNDESIRED, |
|---|
| 1139 | + * then kernel will disable the HDCP and re-enable with new type in the |
|---|
| 1140 | + * same atomic commit. And when "Content Protection" is ENABLED, it means |
|---|
| 1141 | + * that link is HDCP authenticated and encrypted, for the transmission of |
|---|
| 1142 | + * the Type of stream mentioned at "HDCP Content Type". |
|---|
| 1143 | + * |
|---|
| 1144 | + * HDR_OUTPUT_METADATA: |
|---|
| 1145 | + * Connector property to enable userspace to send HDR Metadata to |
|---|
| 1146 | + * driver. This metadata is based on the composition and blending |
|---|
| 1147 | + * policies decided by user, taking into account the hardware and |
|---|
| 1148 | + * sink capabilities. The driver gets this metadata and creates a |
|---|
| 1149 | + * Dynamic Range and Mastering Infoframe (DRM) in case of HDMI, |
|---|
| 1150 | + * SDP packet (Non-audio INFOFRAME SDP v1.3) for DP. This is then |
|---|
| 1151 | + * sent to sink. This notifies the sink of the upcoming frame's Color |
|---|
| 1152 | + * Encoding and Luminance parameters. |
|---|
| 1153 | + * |
|---|
| 1154 | + * Userspace first need to detect the HDR capabilities of sink by |
|---|
| 1155 | + * reading and parsing the EDID. Details of HDR metadata for HDMI |
|---|
| 1156 | + * are added in CTA 861.G spec. For DP , its defined in VESA DP |
|---|
| 1157 | + * Standard v1.4. It needs to then get the metadata information |
|---|
| 1158 | + * of the video/game/app content which are encoded in HDR (basically |
|---|
| 1159 | + * using HDR transfer functions). With this information it needs to |
|---|
| 1160 | + * decide on a blending policy and compose the relevant |
|---|
| 1161 | + * layers/overlays into a common format. Once this blending is done, |
|---|
| 1162 | + * userspace will be aware of the metadata of the composed frame to |
|---|
| 1163 | + * be send to sink. It then uses this property to communicate this |
|---|
| 1164 | + * metadata to driver which then make a Infoframe packet and sends |
|---|
| 1165 | + * to sink based on the type of encoder connected. |
|---|
| 1166 | + * |
|---|
| 1167 | + * Userspace will be responsible to do Tone mapping operation in case: |
|---|
| 1168 | + * - Some layers are HDR and others are SDR |
|---|
| 1169 | + * - HDR layers luminance is not same as sink |
|---|
| 1170 | + * |
|---|
| 1171 | + * It will even need to do colorspace conversion and get all layers |
|---|
| 1172 | + * to one common colorspace for blending. It can use either GL, Media |
|---|
| 1173 | + * or display engine to get this done based on the capabilities of the |
|---|
| 1174 | + * associated hardware. |
|---|
| 1175 | + * |
|---|
| 1176 | + * Driver expects metadata to be put in &struct hdr_output_metadata |
|---|
| 1177 | + * structure from userspace. This is received as blob and stored in |
|---|
| 1178 | + * &drm_connector_state.hdr_output_metadata. It parses EDID and saves the |
|---|
| 1179 | + * sink metadata in &struct hdr_sink_metadata, as |
|---|
| 1180 | + * &drm_connector.hdr_sink_metadata. Driver uses |
|---|
| 1181 | + * drm_hdmi_infoframe_set_hdr_metadata() helper to set the HDR metadata, |
|---|
| 1182 | + * hdmi_drm_infoframe_pack() to pack the infoframe as per spec, in case of |
|---|
| 1183 | + * HDMI encoder. |
|---|
| 1184 | + * |
|---|
| 1185 | + * max bpc: |
|---|
| 1186 | + * This range property is used by userspace to limit the bit depth. When |
|---|
| 1187 | + * used the driver would limit the bpc in accordance with the valid range |
|---|
| 1188 | + * supported by the hardware and sink. Drivers to use the function |
|---|
| 1189 | + * drm_connector_attach_max_bpc_property() to create and attach the |
|---|
| 1190 | + * property to the connector during initialization. |
|---|
| 982 | 1191 | * |
|---|
| 983 | 1192 | * Connectors also have one standardized atomic property: |
|---|
| 984 | 1193 | * |
|---|
| .. | .. |
|---|
| 996 | 1205 | * coordinates, so if userspace rotates the picture to adjust for |
|---|
| 997 | 1206 | * the orientation it must also apply the same transformation to the |
|---|
| 998 | 1207 | * touchscreen input coordinates. This property is initialized by calling |
|---|
| 999 | | - * drm_connector_init_panel_orientation_property(). |
|---|
| 1208 | + * drm_connector_set_panel_orientation() or |
|---|
| 1209 | + * drm_connector_set_panel_orientation_with_quirk() |
|---|
| 1000 | 1210 | * |
|---|
| 1001 | 1211 | * scaling mode: |
|---|
| 1002 | 1212 | * This property defines how a non-native mode is upscaled to the native |
|---|
| .. | .. |
|---|
| 1020 | 1230 | * can also expose this property to external outputs, in which case they |
|---|
| 1021 | 1231 | * must support "None", which should be the default (since external screens |
|---|
| 1022 | 1232 | * have a built-in scaler). |
|---|
| 1233 | + * |
|---|
| 1234 | + * subconnector: |
|---|
| 1235 | + * This property is used by DVI-I, TVout and DisplayPort to indicate different |
|---|
| 1236 | + * connector subtypes. Enum values more or less match with those from main |
|---|
| 1237 | + * connector types. |
|---|
| 1238 | + * For DVI-I and TVout there is also a matching property "select subconnector" |
|---|
| 1239 | + * allowing to switch between signal types. |
|---|
| 1240 | + * DP subconnector corresponds to a downstream port. |
|---|
| 1023 | 1241 | */ |
|---|
| 1024 | 1242 | |
|---|
| 1025 | 1243 | int drm_connector_create_standard_properties(struct drm_device *dev) |
|---|
| .. | .. |
|---|
| 1109 | 1327 | EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); |
|---|
| 1110 | 1328 | |
|---|
| 1111 | 1329 | /** |
|---|
| 1330 | + * drm_connector_attach_dp_subconnector_property - create subconnector property for DP |
|---|
| 1331 | + * @connector: drm_connector to attach property |
|---|
| 1332 | + * |
|---|
| 1333 | + * Called by a driver when DP connector is created. |
|---|
| 1334 | + */ |
|---|
| 1335 | +void drm_connector_attach_dp_subconnector_property(struct drm_connector *connector) |
|---|
| 1336 | +{ |
|---|
| 1337 | + struct drm_mode_config *mode_config = &connector->dev->mode_config; |
|---|
| 1338 | + |
|---|
| 1339 | + if (!mode_config->dp_subconnector_property) |
|---|
| 1340 | + mode_config->dp_subconnector_property = |
|---|
| 1341 | + drm_property_create_enum(connector->dev, |
|---|
| 1342 | + DRM_MODE_PROP_IMMUTABLE, |
|---|
| 1343 | + "subconnector", |
|---|
| 1344 | + drm_dp_subconnector_enum_list, |
|---|
| 1345 | + ARRAY_SIZE(drm_dp_subconnector_enum_list)); |
|---|
| 1346 | + |
|---|
| 1347 | + drm_object_attach_property(&connector->base, |
|---|
| 1348 | + mode_config->dp_subconnector_property, |
|---|
| 1349 | + DRM_MODE_SUBCONNECTOR_Unknown); |
|---|
| 1350 | +} |
|---|
| 1351 | +EXPORT_SYMBOL(drm_connector_attach_dp_subconnector_property); |
|---|
| 1352 | + |
|---|
| 1353 | +/** |
|---|
| 1112 | 1354 | * DOC: HDMI connector properties |
|---|
| 1113 | 1355 | * |
|---|
| 1114 | 1356 | * content type (HDMI specific): |
|---|
| 1115 | 1357 | * Indicates content type setting to be used in HDMI infoframes to indicate |
|---|
| 1116 | | - * content type for the external device, so that it adjusts it's display |
|---|
| 1358 | + * content type for the external device, so that it adjusts its display |
|---|
| 1117 | 1359 | * settings accordingly. |
|---|
| 1118 | 1360 | * |
|---|
| 1119 | 1361 | * The value of this property can be one of the following: |
|---|
| .. | .. |
|---|
| 1185 | 1427 | EXPORT_SYMBOL(drm_hdmi_avi_infoframe_content_type); |
|---|
| 1186 | 1428 | |
|---|
| 1187 | 1429 | /** |
|---|
| 1188 | | - * drm_create_tv_properties - create TV specific connector properties |
|---|
| 1430 | + * drm_mode_attach_tv_margin_properties - attach TV connector margin properties |
|---|
| 1431 | + * @connector: DRM connector |
|---|
| 1432 | + * |
|---|
| 1433 | + * Called by a driver when it needs to attach TV margin props to a connector. |
|---|
| 1434 | + * Typically used on SDTV and HDMI connectors. |
|---|
| 1435 | + */ |
|---|
| 1436 | +void drm_connector_attach_tv_margin_properties(struct drm_connector *connector) |
|---|
| 1437 | +{ |
|---|
| 1438 | + struct drm_device *dev = connector->dev; |
|---|
| 1439 | + |
|---|
| 1440 | + drm_object_attach_property(&connector->base, |
|---|
| 1441 | + dev->mode_config.tv_left_margin_property, |
|---|
| 1442 | + 0); |
|---|
| 1443 | + drm_object_attach_property(&connector->base, |
|---|
| 1444 | + dev->mode_config.tv_right_margin_property, |
|---|
| 1445 | + 0); |
|---|
| 1446 | + drm_object_attach_property(&connector->base, |
|---|
| 1447 | + dev->mode_config.tv_top_margin_property, |
|---|
| 1448 | + 0); |
|---|
| 1449 | + drm_object_attach_property(&connector->base, |
|---|
| 1450 | + dev->mode_config.tv_bottom_margin_property, |
|---|
| 1451 | + 0); |
|---|
| 1452 | +} |
|---|
| 1453 | +EXPORT_SYMBOL(drm_connector_attach_tv_margin_properties); |
|---|
| 1454 | + |
|---|
| 1455 | +/** |
|---|
| 1456 | + * drm_mode_create_tv_margin_properties - create TV connector margin properties |
|---|
| 1457 | + * @dev: DRM device |
|---|
| 1458 | + * |
|---|
| 1459 | + * Called by a driver's HDMI connector initialization routine, this function |
|---|
| 1460 | + * creates the TV margin properties for a given device. No need to call this |
|---|
| 1461 | + * function for an SDTV connector, it's already called from |
|---|
| 1462 | + * drm_mode_create_tv_properties(). |
|---|
| 1463 | + */ |
|---|
| 1464 | +int drm_mode_create_tv_margin_properties(struct drm_device *dev) |
|---|
| 1465 | +{ |
|---|
| 1466 | + if (dev->mode_config.tv_left_margin_property) |
|---|
| 1467 | + return 0; |
|---|
| 1468 | + |
|---|
| 1469 | + dev->mode_config.tv_left_margin_property = |
|---|
| 1470 | + drm_property_create_range(dev, 0, "left margin", 0, 100); |
|---|
| 1471 | + if (!dev->mode_config.tv_left_margin_property) |
|---|
| 1472 | + return -ENOMEM; |
|---|
| 1473 | + |
|---|
| 1474 | + dev->mode_config.tv_right_margin_property = |
|---|
| 1475 | + drm_property_create_range(dev, 0, "right margin", 0, 100); |
|---|
| 1476 | + if (!dev->mode_config.tv_right_margin_property) |
|---|
| 1477 | + return -ENOMEM; |
|---|
| 1478 | + |
|---|
| 1479 | + dev->mode_config.tv_top_margin_property = |
|---|
| 1480 | + drm_property_create_range(dev, 0, "top margin", 0, 100); |
|---|
| 1481 | + if (!dev->mode_config.tv_top_margin_property) |
|---|
| 1482 | + return -ENOMEM; |
|---|
| 1483 | + |
|---|
| 1484 | + dev->mode_config.tv_bottom_margin_property = |
|---|
| 1485 | + drm_property_create_range(dev, 0, "bottom margin", 0, 100); |
|---|
| 1486 | + if (!dev->mode_config.tv_bottom_margin_property) |
|---|
| 1487 | + return -ENOMEM; |
|---|
| 1488 | + |
|---|
| 1489 | + return 0; |
|---|
| 1490 | +} |
|---|
| 1491 | +EXPORT_SYMBOL(drm_mode_create_tv_margin_properties); |
|---|
| 1492 | + |
|---|
| 1493 | +/** |
|---|
| 1494 | + * drm_mode_create_tv_properties - create TV specific connector properties |
|---|
| 1189 | 1495 | * @dev: DRM device |
|---|
| 1190 | 1496 | * @num_modes: number of different TV formats (modes) supported |
|---|
| 1191 | 1497 | * @modes: array of pointers to strings containing name of each format |
|---|
| .. | .. |
|---|
| 1230 | 1536 | /* |
|---|
| 1231 | 1537 | * Other, TV specific properties: margins & TV modes. |
|---|
| 1232 | 1538 | */ |
|---|
| 1233 | | - dev->mode_config.tv_left_margin_property = |
|---|
| 1234 | | - drm_property_create_range(dev, 0, "left margin", 0, 100); |
|---|
| 1235 | | - if (!dev->mode_config.tv_left_margin_property) |
|---|
| 1236 | | - goto nomem; |
|---|
| 1237 | | - |
|---|
| 1238 | | - dev->mode_config.tv_right_margin_property = |
|---|
| 1239 | | - drm_property_create_range(dev, 0, "right margin", 0, 100); |
|---|
| 1240 | | - if (!dev->mode_config.tv_right_margin_property) |
|---|
| 1241 | | - goto nomem; |
|---|
| 1242 | | - |
|---|
| 1243 | | - dev->mode_config.tv_top_margin_property = |
|---|
| 1244 | | - drm_property_create_range(dev, 0, "top margin", 0, 100); |
|---|
| 1245 | | - if (!dev->mode_config.tv_top_margin_property) |
|---|
| 1246 | | - goto nomem; |
|---|
| 1247 | | - |
|---|
| 1248 | | - dev->mode_config.tv_bottom_margin_property = |
|---|
| 1249 | | - drm_property_create_range(dev, 0, "bottom margin", 0, 100); |
|---|
| 1250 | | - if (!dev->mode_config.tv_bottom_margin_property) |
|---|
| 1539 | + if (drm_mode_create_tv_margin_properties(dev)) |
|---|
| 1251 | 1540 | goto nomem; |
|---|
| 1252 | 1541 | |
|---|
| 1253 | 1542 | dev->mode_config.tv_mode_property = |
|---|
| .. | .. |
|---|
| 1326 | 1615 | EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); |
|---|
| 1327 | 1616 | |
|---|
| 1328 | 1617 | /** |
|---|
| 1618 | + * DOC: Variable refresh properties |
|---|
| 1619 | + * |
|---|
| 1620 | + * Variable refresh rate capable displays can dynamically adjust their |
|---|
| 1621 | + * refresh rate by extending the duration of their vertical front porch |
|---|
| 1622 | + * until page flip or timeout occurs. This can reduce or remove stuttering |
|---|
| 1623 | + * and latency in scenarios where the page flip does not align with the |
|---|
| 1624 | + * vblank interval. |
|---|
| 1625 | + * |
|---|
| 1626 | + * An example scenario would be an application flipping at a constant rate |
|---|
| 1627 | + * of 48Hz on a 60Hz display. The page flip will frequently miss the vblank |
|---|
| 1628 | + * interval and the same contents will be displayed twice. This can be |
|---|
| 1629 | + * observed as stuttering for content with motion. |
|---|
| 1630 | + * |
|---|
| 1631 | + * If variable refresh rate was active on a display that supported a |
|---|
| 1632 | + * variable refresh range from 35Hz to 60Hz no stuttering would be observable |
|---|
| 1633 | + * for the example scenario. The minimum supported variable refresh rate of |
|---|
| 1634 | + * 35Hz is below the page flip frequency and the vertical front porch can |
|---|
| 1635 | + * be extended until the page flip occurs. The vblank interval will be |
|---|
| 1636 | + * directly aligned to the page flip rate. |
|---|
| 1637 | + * |
|---|
| 1638 | + * Not all userspace content is suitable for use with variable refresh rate. |
|---|
| 1639 | + * Large and frequent changes in vertical front porch duration may worsen |
|---|
| 1640 | + * perceived stuttering for input sensitive applications. |
|---|
| 1641 | + * |
|---|
| 1642 | + * Panel brightness will also vary with vertical front porch duration. Some |
|---|
| 1643 | + * panels may have noticeable differences in brightness between the minimum |
|---|
| 1644 | + * vertical front porch duration and the maximum vertical front porch duration. |
|---|
| 1645 | + * Large and frequent changes in vertical front porch duration may produce |
|---|
| 1646 | + * observable flickering for such panels. |
|---|
| 1647 | + * |
|---|
| 1648 | + * Userspace control for variable refresh rate is supported via properties |
|---|
| 1649 | + * on the &drm_connector and &drm_crtc objects. |
|---|
| 1650 | + * |
|---|
| 1651 | + * "vrr_capable": |
|---|
| 1652 | + * Optional &drm_connector boolean property that drivers should attach |
|---|
| 1653 | + * with drm_connector_attach_vrr_capable_property() on connectors that |
|---|
| 1654 | + * could support variable refresh rates. Drivers should update the |
|---|
| 1655 | + * property value by calling drm_connector_set_vrr_capable_property(). |
|---|
| 1656 | + * |
|---|
| 1657 | + * Absence of the property should indicate absence of support. |
|---|
| 1658 | + * |
|---|
| 1659 | + * "VRR_ENABLED": |
|---|
| 1660 | + * Default &drm_crtc boolean property that notifies the driver that the |
|---|
| 1661 | + * content on the CRTC is suitable for variable refresh rate presentation. |
|---|
| 1662 | + * The driver will take this property as a hint to enable variable |
|---|
| 1663 | + * refresh rate support if the receiver supports it, ie. if the |
|---|
| 1664 | + * "vrr_capable" property is true on the &drm_connector object. The |
|---|
| 1665 | + * vertical front porch duration will be extended until page-flip or |
|---|
| 1666 | + * timeout when enabled. |
|---|
| 1667 | + * |
|---|
| 1668 | + * The minimum vertical front porch duration is defined as the vertical |
|---|
| 1669 | + * front porch duration for the current mode. |
|---|
| 1670 | + * |
|---|
| 1671 | + * The maximum vertical front porch duration is greater than or equal to |
|---|
| 1672 | + * the minimum vertical front porch duration. The duration is derived |
|---|
| 1673 | + * from the minimum supported variable refresh rate for the connector. |
|---|
| 1674 | + * |
|---|
| 1675 | + * The driver may place further restrictions within these minimum |
|---|
| 1676 | + * and maximum bounds. |
|---|
| 1677 | + */ |
|---|
| 1678 | + |
|---|
| 1679 | +/** |
|---|
| 1680 | + * drm_connector_attach_vrr_capable_property - creates the |
|---|
| 1681 | + * vrr_capable property |
|---|
| 1682 | + * @connector: connector to create the vrr_capable property on. |
|---|
| 1683 | + * |
|---|
| 1684 | + * This is used by atomic drivers to add support for querying |
|---|
| 1685 | + * variable refresh rate capability for a connector. |
|---|
| 1686 | + * |
|---|
| 1687 | + * Returns: |
|---|
| 1688 | + * Zero on success, negative errno on failure. |
|---|
| 1689 | + */ |
|---|
| 1690 | +int drm_connector_attach_vrr_capable_property( |
|---|
| 1691 | + struct drm_connector *connector) |
|---|
| 1692 | +{ |
|---|
| 1693 | + struct drm_device *dev = connector->dev; |
|---|
| 1694 | + struct drm_property *prop; |
|---|
| 1695 | + |
|---|
| 1696 | + if (!connector->vrr_capable_property) { |
|---|
| 1697 | + prop = drm_property_create_bool(dev, DRM_MODE_PROP_IMMUTABLE, |
|---|
| 1698 | + "vrr_capable"); |
|---|
| 1699 | + if (!prop) |
|---|
| 1700 | + return -ENOMEM; |
|---|
| 1701 | + |
|---|
| 1702 | + connector->vrr_capable_property = prop; |
|---|
| 1703 | + drm_object_attach_property(&connector->base, prop, 0); |
|---|
| 1704 | + } |
|---|
| 1705 | + |
|---|
| 1706 | + return 0; |
|---|
| 1707 | +} |
|---|
| 1708 | +EXPORT_SYMBOL(drm_connector_attach_vrr_capable_property); |
|---|
| 1709 | + |
|---|
| 1710 | +/** |
|---|
| 1329 | 1711 | * drm_connector_attach_scaling_mode_property - attach atomic scaling mode property |
|---|
| 1330 | 1712 | * @connector: connector to attach scaling mode property on. |
|---|
| 1331 | 1713 | * @scaling_mode_mask: or'ed mask of BIT(%DRM_MODE_SCALE_\*). |
|---|
| .. | .. |
|---|
| 1386 | 1768 | EXPORT_SYMBOL(drm_connector_attach_scaling_mode_property); |
|---|
| 1387 | 1769 | |
|---|
| 1388 | 1770 | /** |
|---|
| 1389 | | - * drm_connector_attach_content_protection_property - attach content protection |
|---|
| 1390 | | - * property |
|---|
| 1391 | | - * |
|---|
| 1392 | | - * @connector: connector to attach CP property on. |
|---|
| 1393 | | - * |
|---|
| 1394 | | - * This is used to add support for content protection on select connectors. |
|---|
| 1395 | | - * Content Protection is intentionally vague to allow for different underlying |
|---|
| 1396 | | - * technologies, however it is most implemented by HDCP. |
|---|
| 1397 | | - * |
|---|
| 1398 | | - * The content protection will be set to &drm_connector_state.content_protection |
|---|
| 1399 | | - * |
|---|
| 1400 | | - * Returns: |
|---|
| 1401 | | - * Zero on success, negative errno on failure. |
|---|
| 1402 | | - */ |
|---|
| 1403 | | -int drm_connector_attach_content_protection_property( |
|---|
| 1404 | | - struct drm_connector *connector) |
|---|
| 1405 | | -{ |
|---|
| 1406 | | - struct drm_device *dev = connector->dev; |
|---|
| 1407 | | - struct drm_property *prop; |
|---|
| 1408 | | - |
|---|
| 1409 | | - prop = drm_property_create_enum(dev, 0, "Content Protection", |
|---|
| 1410 | | - drm_cp_enum_list, |
|---|
| 1411 | | - ARRAY_SIZE(drm_cp_enum_list)); |
|---|
| 1412 | | - if (!prop) |
|---|
| 1413 | | - return -ENOMEM; |
|---|
| 1414 | | - |
|---|
| 1415 | | - drm_object_attach_property(&connector->base, prop, |
|---|
| 1416 | | - DRM_MODE_CONTENT_PROTECTION_UNDESIRED); |
|---|
| 1417 | | - |
|---|
| 1418 | | - connector->content_protection_property = prop; |
|---|
| 1419 | | - |
|---|
| 1420 | | - return 0; |
|---|
| 1421 | | -} |
|---|
| 1422 | | -EXPORT_SYMBOL(drm_connector_attach_content_protection_property); |
|---|
| 1423 | | - |
|---|
| 1424 | | -/** |
|---|
| 1425 | 1771 | * drm_mode_create_aspect_ratio_property - create aspect ratio property |
|---|
| 1426 | 1772 | * @dev: DRM device |
|---|
| 1427 | 1773 | * |
|---|
| .. | .. |
|---|
| 1452 | 1798 | * DOC: standard connector properties |
|---|
| 1453 | 1799 | * |
|---|
| 1454 | 1800 | * Colorspace: |
|---|
| 1455 | | - * drm_mode_create_colorspace_property - create colorspace property |
|---|
| 1456 | 1801 | * This property helps select a suitable colorspace based on the sink |
|---|
| 1457 | 1802 | * capability. Modern sink devices support wider gamut like BT2020. |
|---|
| 1458 | 1803 | * This helps switch to BT2020 mode if the BT2020 encoded video stream |
|---|
| .. | .. |
|---|
| 1472 | 1817 | * - This property is just to inform sink what colorspace |
|---|
| 1473 | 1818 | * source is trying to drive. |
|---|
| 1474 | 1819 | * |
|---|
| 1475 | | - * Called by a driver the first time it's needed, must be attached to desired |
|---|
| 1476 | | - * connectors. |
|---|
| 1820 | + * Because between HDMI and DP have different colorspaces, |
|---|
| 1821 | + * drm_mode_create_hdmi_colorspace_property() is used for HDMI connector and |
|---|
| 1822 | + * drm_mode_create_dp_colorspace_property() is used for DP connector. |
|---|
| 1477 | 1823 | */ |
|---|
| 1478 | | -int drm_mode_create_colorspace_property(struct drm_connector *connector) |
|---|
| 1824 | + |
|---|
| 1825 | +/** |
|---|
| 1826 | + * drm_mode_create_hdmi_colorspace_property - create hdmi colorspace property |
|---|
| 1827 | + * @connector: connector to create the Colorspace property on. |
|---|
| 1828 | + * |
|---|
| 1829 | + * Called by a driver the first time it's needed, must be attached to desired |
|---|
| 1830 | + * HDMI connectors. |
|---|
| 1831 | + * |
|---|
| 1832 | + * Returns: |
|---|
| 1833 | + * Zero on success, negative errno on failure. |
|---|
| 1834 | + */ |
|---|
| 1835 | +int drm_mode_create_hdmi_colorspace_property(struct drm_connector *connector) |
|---|
| 1479 | 1836 | { |
|---|
| 1480 | 1837 | struct drm_device *dev = connector->dev; |
|---|
| 1481 | | - struct drm_property *prop; |
|---|
| 1482 | 1838 | |
|---|
| 1483 | | - if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || |
|---|
| 1484 | | - connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) { |
|---|
| 1485 | | - prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, |
|---|
| 1486 | | - "Colorspace", |
|---|
| 1487 | | - hdmi_colorspaces, |
|---|
| 1488 | | - ARRAY_SIZE(hdmi_colorspaces)); |
|---|
| 1489 | | - if (!prop) |
|---|
| 1490 | | - return -ENOMEM; |
|---|
| 1491 | | - } else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP || |
|---|
| 1492 | | - connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { |
|---|
| 1493 | | - prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, |
|---|
| 1494 | | - "Colorspace", dp_colorspaces, |
|---|
| 1495 | | - ARRAY_SIZE(dp_colorspaces)); |
|---|
| 1496 | | - |
|---|
| 1497 | | - if (!prop) |
|---|
| 1498 | | - return -ENOMEM; |
|---|
| 1499 | | - } else { |
|---|
| 1500 | | - DRM_DEBUG_KMS("Colorspace property not supported\n"); |
|---|
| 1839 | + if (connector->colorspace_property) |
|---|
| 1501 | 1840 | return 0; |
|---|
| 1502 | | - } |
|---|
| 1503 | 1841 | |
|---|
| 1504 | | - connector->colorspace_property = prop; |
|---|
| 1842 | + connector->colorspace_property = |
|---|
| 1843 | + drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "Colorspace", |
|---|
| 1844 | + hdmi_colorspaces, |
|---|
| 1845 | + ARRAY_SIZE(hdmi_colorspaces)); |
|---|
| 1846 | + |
|---|
| 1847 | + if (!connector->colorspace_property) |
|---|
| 1848 | + return -ENOMEM; |
|---|
| 1505 | 1849 | |
|---|
| 1506 | 1850 | return 0; |
|---|
| 1507 | 1851 | } |
|---|
| 1508 | | -EXPORT_SYMBOL(drm_mode_create_colorspace_property); |
|---|
| 1852 | +EXPORT_SYMBOL(drm_mode_create_hdmi_colorspace_property); |
|---|
| 1853 | + |
|---|
| 1854 | +/** |
|---|
| 1855 | + * drm_mode_create_dp_colorspace_property - create dp colorspace property |
|---|
| 1856 | + * @connector: connector to create the Colorspace property on. |
|---|
| 1857 | + * |
|---|
| 1858 | + * Called by a driver the first time it's needed, must be attached to desired |
|---|
| 1859 | + * DP connectors. |
|---|
| 1860 | + * |
|---|
| 1861 | + * Returns: |
|---|
| 1862 | + * Zero on success, negative errno on failure. |
|---|
| 1863 | + */ |
|---|
| 1864 | +int drm_mode_create_dp_colorspace_property(struct drm_connector *connector) |
|---|
| 1865 | +{ |
|---|
| 1866 | + struct drm_device *dev = connector->dev; |
|---|
| 1867 | + |
|---|
| 1868 | + if (connector->colorspace_property) |
|---|
| 1869 | + return 0; |
|---|
| 1870 | + |
|---|
| 1871 | + connector->colorspace_property = |
|---|
| 1872 | + drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "Colorspace", |
|---|
| 1873 | + dp_colorspaces, |
|---|
| 1874 | + ARRAY_SIZE(dp_colorspaces)); |
|---|
| 1875 | + |
|---|
| 1876 | + if (!connector->colorspace_property) |
|---|
| 1877 | + return -ENOMEM; |
|---|
| 1878 | + |
|---|
| 1879 | + return 0; |
|---|
| 1880 | +} |
|---|
| 1881 | +EXPORT_SYMBOL(drm_mode_create_dp_colorspace_property); |
|---|
| 1509 | 1882 | |
|---|
| 1510 | 1883 | /** |
|---|
| 1511 | 1884 | * drm_mode_create_content_type_property - create content type property |
|---|
| .. | .. |
|---|
| 1538 | 1911 | * drm_mode_create_suggested_offset_properties - create suggests offset properties |
|---|
| 1539 | 1912 | * @dev: DRM device |
|---|
| 1540 | 1913 | * |
|---|
| 1541 | | - * Create the the suggested x/y offset property for connectors. |
|---|
| 1914 | + * Create the suggested x/y offset property for connectors. |
|---|
| 1542 | 1915 | */ |
|---|
| 1543 | 1916 | int drm_mode_create_suggested_offset_properties(struct drm_device *dev) |
|---|
| 1544 | 1917 | { |
|---|
| .. | .. |
|---|
| 1594 | 1967 | * This looks up the tile information for a connector, and creates a |
|---|
| 1595 | 1968 | * property for userspace to parse if it exists. The property is of |
|---|
| 1596 | 1969 | * the form of 8 integers using ':' as a separator. |
|---|
| 1970 | + * This is used for dual port tiled displays with DisplayPort SST |
|---|
| 1971 | + * or DisplayPort MST connectors. |
|---|
| 1597 | 1972 | * |
|---|
| 1598 | 1973 | * Returns: |
|---|
| 1599 | 1974 | * Zero on success, errno on failure. |
|---|
| .. | .. |
|---|
| 1637 | 2012 | * |
|---|
| 1638 | 2013 | * This function creates a new blob modeset object and assigns its id to the |
|---|
| 1639 | 2014 | * connector's edid property. |
|---|
| 2015 | + * Since we also parse tile information from EDID's displayID block, we also |
|---|
| 2016 | + * set the connector's tile property here. See drm_connector_set_tile_property() |
|---|
| 2017 | + * for more details. |
|---|
| 1640 | 2018 | * |
|---|
| 1641 | 2019 | * Returns: |
|---|
| 1642 | 2020 | * Zero on success, negative errno on failure. |
|---|
| .. | .. |
|---|
| 1647 | 2025 | struct drm_device *dev = connector->dev; |
|---|
| 1648 | 2026 | size_t size = 0; |
|---|
| 1649 | 2027 | int ret; |
|---|
| 2028 | + const struct edid *old_edid; |
|---|
| 1650 | 2029 | |
|---|
| 1651 | 2030 | /* ignore requests to set edid when overridden */ |
|---|
| 1652 | 2031 | if (connector->override_edid) |
|---|
| .. | .. |
|---|
| 1656 | 2035 | size = EDID_LENGTH * (1 + edid->extensions); |
|---|
| 1657 | 2036 | |
|---|
| 1658 | 2037 | /* Set the display info, using edid if available, otherwise |
|---|
| 1659 | | - * reseting the values to defaults. This duplicates the work |
|---|
| 2038 | + * resetting the values to defaults. This duplicates the work |
|---|
| 1660 | 2039 | * done in drm_add_edid_modes, but that function is not |
|---|
| 1661 | 2040 | * consistently called before this one in all drivers and the |
|---|
| 1662 | 2041 | * computation is cheap enough that it seems better to |
|---|
| .. | .. |
|---|
| 1668 | 2047 | else |
|---|
| 1669 | 2048 | drm_reset_display_info(connector); |
|---|
| 1670 | 2049 | |
|---|
| 2050 | + drm_update_tile_info(connector, edid); |
|---|
| 2051 | + |
|---|
| 2052 | + if (connector->edid_blob_ptr) { |
|---|
| 2053 | + old_edid = (const struct edid *)connector->edid_blob_ptr->data; |
|---|
| 2054 | + if (old_edid) { |
|---|
| 2055 | + if (!drm_edid_are_equal(edid, old_edid)) { |
|---|
| 2056 | + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Edid was changed.\n", |
|---|
| 2057 | + connector->base.id, connector->name); |
|---|
| 2058 | + |
|---|
| 2059 | + connector->epoch_counter += 1; |
|---|
| 2060 | + DRM_DEBUG_KMS("Updating change counter to %llu\n", |
|---|
| 2061 | + connector->epoch_counter); |
|---|
| 2062 | + } |
|---|
| 2063 | + } |
|---|
| 2064 | + } |
|---|
| 2065 | + |
|---|
| 1671 | 2066 | drm_object_property_set_value(&connector->base, |
|---|
| 1672 | 2067 | dev->mode_config.non_desktop_property, |
|---|
| 1673 | 2068 | connector->display_info.non_desktop); |
|---|
| .. | .. |
|---|
| 1678 | 2073 | edid, |
|---|
| 1679 | 2074 | &connector->base, |
|---|
| 1680 | 2075 | dev->mode_config.edid_property); |
|---|
| 1681 | | - return ret; |
|---|
| 2076 | + if (ret) |
|---|
| 2077 | + return ret; |
|---|
| 2078 | + return drm_connector_set_tile_property(connector); |
|---|
| 1682 | 2079 | } |
|---|
| 1683 | 2080 | EXPORT_SYMBOL(drm_connector_update_edid_property); |
|---|
| 1684 | 2081 | |
|---|
| .. | .. |
|---|
| 1713 | 2110 | EXPORT_SYMBOL(drm_connector_set_link_status_property); |
|---|
| 1714 | 2111 | |
|---|
| 1715 | 2112 | /** |
|---|
| 1716 | | - * drm_connector_init_panel_orientation_property - |
|---|
| 1717 | | - * initialize the connecters panel_orientation property |
|---|
| 1718 | | - * @connector: connector for which to init the panel-orientation property. |
|---|
| 1719 | | - * @width: width in pixels of the panel, used for panel quirk detection |
|---|
| 1720 | | - * @height: height in pixels of the panel, used for panel quirk detection |
|---|
| 2113 | + * drm_connector_attach_max_bpc_property - attach "max bpc" property |
|---|
| 2114 | + * @connector: connector to attach max bpc property on. |
|---|
| 2115 | + * @min: The minimum bit depth supported by the connector. |
|---|
| 2116 | + * @max: The maximum bit depth supported by the connector. |
|---|
| 1721 | 2117 | * |
|---|
| 1722 | | - * This function should only be called for built-in panels, after setting |
|---|
| 1723 | | - * connector->display_info.panel_orientation first (if known). |
|---|
| 1724 | | - * |
|---|
| 1725 | | - * This function will check for platform specific (e.g. DMI based) quirks |
|---|
| 1726 | | - * overriding display_info.panel_orientation first, then if panel_orientation |
|---|
| 1727 | | - * is not DRM_MODE_PANEL_ORIENTATION_UNKNOWN it will attach the |
|---|
| 1728 | | - * "panel orientation" property to the connector. |
|---|
| 2118 | + * This is used to add support for limiting the bit depth on a connector. |
|---|
| 1729 | 2119 | * |
|---|
| 1730 | 2120 | * Returns: |
|---|
| 1731 | 2121 | * Zero on success, negative errno on failure. |
|---|
| 1732 | 2122 | */ |
|---|
| 1733 | | -int drm_connector_init_panel_orientation_property( |
|---|
| 1734 | | - struct drm_connector *connector, int width, int height) |
|---|
| 2123 | +int drm_connector_attach_max_bpc_property(struct drm_connector *connector, |
|---|
| 2124 | + int min, int max) |
|---|
| 2125 | +{ |
|---|
| 2126 | + struct drm_device *dev = connector->dev; |
|---|
| 2127 | + struct drm_property *prop; |
|---|
| 2128 | + |
|---|
| 2129 | + prop = connector->max_bpc_property; |
|---|
| 2130 | + if (!prop) { |
|---|
| 2131 | + prop = drm_property_create_range(dev, 0, "max bpc", min, max); |
|---|
| 2132 | + if (!prop) |
|---|
| 2133 | + return -ENOMEM; |
|---|
| 2134 | + |
|---|
| 2135 | + connector->max_bpc_property = prop; |
|---|
| 2136 | + } |
|---|
| 2137 | + |
|---|
| 2138 | + drm_object_attach_property(&connector->base, prop, max); |
|---|
| 2139 | + connector->state->max_requested_bpc = max; |
|---|
| 2140 | + connector->state->max_bpc = max; |
|---|
| 2141 | + |
|---|
| 2142 | + return 0; |
|---|
| 2143 | +} |
|---|
| 2144 | +EXPORT_SYMBOL(drm_connector_attach_max_bpc_property); |
|---|
| 2145 | + |
|---|
| 2146 | +/** |
|---|
| 2147 | + * drm_connector_set_vrr_capable_property - sets the variable refresh rate |
|---|
| 2148 | + * capable property for a connector |
|---|
| 2149 | + * @connector: drm connector |
|---|
| 2150 | + * @capable: True if the connector is variable refresh rate capable |
|---|
| 2151 | + * |
|---|
| 2152 | + * Should be used by atomic drivers to update the indicated support for |
|---|
| 2153 | + * variable refresh rate over a connector. |
|---|
| 2154 | + */ |
|---|
| 2155 | +void drm_connector_set_vrr_capable_property( |
|---|
| 2156 | + struct drm_connector *connector, bool capable) |
|---|
| 2157 | +{ |
|---|
| 2158 | + if (!connector->vrr_capable_property) |
|---|
| 2159 | + return; |
|---|
| 2160 | + |
|---|
| 2161 | + drm_object_property_set_value(&connector->base, |
|---|
| 2162 | + connector->vrr_capable_property, |
|---|
| 2163 | + capable); |
|---|
| 2164 | +} |
|---|
| 2165 | +EXPORT_SYMBOL(drm_connector_set_vrr_capable_property); |
|---|
| 2166 | + |
|---|
| 2167 | +/** |
|---|
| 2168 | + * drm_connector_set_panel_orientation - sets the connector's panel_orientation |
|---|
| 2169 | + * @connector: connector for which to set the panel-orientation property. |
|---|
| 2170 | + * @panel_orientation: drm_panel_orientation value to set |
|---|
| 2171 | + * |
|---|
| 2172 | + * This function sets the connector's panel_orientation and attaches |
|---|
| 2173 | + * a "panel orientation" property to the connector. |
|---|
| 2174 | + * |
|---|
| 2175 | + * Calling this function on a connector where the panel_orientation has |
|---|
| 2176 | + * already been set is a no-op (e.g. the orientation has been overridden with |
|---|
| 2177 | + * a kernel commandline option). |
|---|
| 2178 | + * |
|---|
| 2179 | + * It is allowed to call this function with a panel_orientation of |
|---|
| 2180 | + * DRM_MODE_PANEL_ORIENTATION_UNKNOWN, in which case it is a no-op. |
|---|
| 2181 | + * |
|---|
| 2182 | + * Returns: |
|---|
| 2183 | + * Zero on success, negative errno on failure. |
|---|
| 2184 | + */ |
|---|
| 2185 | +int drm_connector_set_panel_orientation( |
|---|
| 2186 | + struct drm_connector *connector, |
|---|
| 2187 | + enum drm_panel_orientation panel_orientation) |
|---|
| 1735 | 2188 | { |
|---|
| 1736 | 2189 | struct drm_device *dev = connector->dev; |
|---|
| 1737 | 2190 | struct drm_display_info *info = &connector->display_info; |
|---|
| 1738 | 2191 | struct drm_property *prop; |
|---|
| 1739 | | - int orientation_quirk; |
|---|
| 1740 | 2192 | |
|---|
| 1741 | | - orientation_quirk = drm_get_panel_orientation_quirk(width, height); |
|---|
| 1742 | | - if (orientation_quirk != DRM_MODE_PANEL_ORIENTATION_UNKNOWN) |
|---|
| 1743 | | - info->panel_orientation = orientation_quirk; |
|---|
| 1744 | | - |
|---|
| 1745 | | - if (info->panel_orientation == DRM_MODE_PANEL_ORIENTATION_UNKNOWN) |
|---|
| 2193 | + /* Already set? */ |
|---|
| 2194 | + if (info->panel_orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN) |
|---|
| 1746 | 2195 | return 0; |
|---|
| 2196 | + |
|---|
| 2197 | + /* Don't attach the property if the orientation is unknown */ |
|---|
| 2198 | + if (panel_orientation == DRM_MODE_PANEL_ORIENTATION_UNKNOWN) |
|---|
| 2199 | + return 0; |
|---|
| 2200 | + |
|---|
| 2201 | + info->panel_orientation = panel_orientation; |
|---|
| 1747 | 2202 | |
|---|
| 1748 | 2203 | prop = dev->mode_config.panel_orientation_property; |
|---|
| 1749 | 2204 | if (!prop) { |
|---|
| .. | .. |
|---|
| 1761 | 2216 | info->panel_orientation); |
|---|
| 1762 | 2217 | return 0; |
|---|
| 1763 | 2218 | } |
|---|
| 1764 | | -EXPORT_SYMBOL(drm_connector_init_panel_orientation_property); |
|---|
| 2219 | +EXPORT_SYMBOL(drm_connector_set_panel_orientation); |
|---|
| 2220 | + |
|---|
| 2221 | +/** |
|---|
| 2222 | + * drm_connector_set_panel_orientation_with_quirk - |
|---|
| 2223 | + * set the connector's panel_orientation after checking for quirks |
|---|
| 2224 | + * @connector: connector for which to init the panel-orientation property. |
|---|
| 2225 | + * @panel_orientation: drm_panel_orientation value to set |
|---|
| 2226 | + * @width: width in pixels of the panel, used for panel quirk detection |
|---|
| 2227 | + * @height: height in pixels of the panel, used for panel quirk detection |
|---|
| 2228 | + * |
|---|
| 2229 | + * Like drm_connector_set_panel_orientation(), but with a check for platform |
|---|
| 2230 | + * specific (e.g. DMI based) quirks overriding the passed in panel_orientation. |
|---|
| 2231 | + * |
|---|
| 2232 | + * Returns: |
|---|
| 2233 | + * Zero on success, negative errno on failure. |
|---|
| 2234 | + */ |
|---|
| 2235 | +int drm_connector_set_panel_orientation_with_quirk( |
|---|
| 2236 | + struct drm_connector *connector, |
|---|
| 2237 | + enum drm_panel_orientation panel_orientation, |
|---|
| 2238 | + int width, int height) |
|---|
| 2239 | +{ |
|---|
| 2240 | + int orientation_quirk; |
|---|
| 2241 | + |
|---|
| 2242 | + orientation_quirk = drm_get_panel_orientation_quirk(width, height); |
|---|
| 2243 | + if (orientation_quirk != DRM_MODE_PANEL_ORIENTATION_UNKNOWN) |
|---|
| 2244 | + panel_orientation = orientation_quirk; |
|---|
| 2245 | + |
|---|
| 2246 | + return drm_connector_set_panel_orientation(connector, |
|---|
| 2247 | + panel_orientation); |
|---|
| 2248 | +} |
|---|
| 2249 | +EXPORT_SYMBOL(drm_connector_set_panel_orientation_with_quirk); |
|---|
| 1765 | 2250 | |
|---|
| 1766 | 2251 | int drm_connector_set_obj_prop(struct drm_mode_object *obj, |
|---|
| 1767 | 2252 | struct drm_property *property, |
|---|
| .. | .. |
|---|
| 1807 | 2292 | |
|---|
| 1808 | 2293 | static bool |
|---|
| 1809 | 2294 | drm_mode_expose_to_userspace(const struct drm_display_mode *mode, |
|---|
| 1810 | | - const struct list_head *export_list, |
|---|
| 2295 | + const struct list_head *modes, |
|---|
| 1811 | 2296 | const struct drm_file *file_priv) |
|---|
| 1812 | 2297 | { |
|---|
| 1813 | 2298 | /* |
|---|
| .. | .. |
|---|
| 1823 | 2308 | * while preparing the list of user-modes. |
|---|
| 1824 | 2309 | */ |
|---|
| 1825 | 2310 | if (!file_priv->aspect_ratio_allowed) { |
|---|
| 1826 | | - struct drm_display_mode *mode_itr; |
|---|
| 2311 | + const struct drm_display_mode *mode_itr; |
|---|
| 1827 | 2312 | |
|---|
| 1828 | | - list_for_each_entry(mode_itr, export_list, export_head) |
|---|
| 1829 | | - if (drm_mode_match(mode_itr, mode, |
|---|
| 2313 | + list_for_each_entry(mode_itr, modes, head) { |
|---|
| 2314 | + if (mode_itr->expose_to_userspace && |
|---|
| 2315 | + drm_mode_match(mode_itr, mode, |
|---|
| 1830 | 2316 | DRM_MODE_MATCH_TIMINGS | |
|---|
| 1831 | 2317 | DRM_MODE_MATCH_CLOCK | |
|---|
| 1832 | 2318 | DRM_MODE_MATCH_FLAGS | |
|---|
| 1833 | 2319 | DRM_MODE_MATCH_3D_FLAGS)) |
|---|
| 1834 | 2320 | return false; |
|---|
| 2321 | + } |
|---|
| 1835 | 2322 | } |
|---|
| 1836 | 2323 | |
|---|
| 1837 | 2324 | return true; |
|---|
| .. | .. |
|---|
| 1848 | 2335 | int encoders_count = 0; |
|---|
| 1849 | 2336 | int ret = 0; |
|---|
| 1850 | 2337 | int copied = 0; |
|---|
| 1851 | | - int i; |
|---|
| 1852 | 2338 | struct drm_mode_modeinfo u_mode; |
|---|
| 1853 | 2339 | struct drm_mode_modeinfo __user *mode_ptr; |
|---|
| 1854 | 2340 | uint32_t __user *encoder_ptr; |
|---|
| 1855 | | - LIST_HEAD(export_list); |
|---|
| 1856 | 2341 | |
|---|
| 1857 | 2342 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
|---|
| 1858 | | - return -EINVAL; |
|---|
| 2343 | + return -EOPNOTSUPP; |
|---|
| 1859 | 2344 | |
|---|
| 1860 | 2345 | memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); |
|---|
| 1861 | 2346 | |
|---|
| .. | .. |
|---|
| 1863 | 2348 | if (!connector) |
|---|
| 1864 | 2349 | return -ENOENT; |
|---|
| 1865 | 2350 | |
|---|
| 1866 | | - drm_connector_for_each_possible_encoder(connector, encoder, i) |
|---|
| 1867 | | - encoders_count++; |
|---|
| 2351 | + encoders_count = hweight32(connector->possible_encoders); |
|---|
| 1868 | 2352 | |
|---|
| 1869 | 2353 | if ((out_resp->count_encoders >= encoders_count) && encoders_count) { |
|---|
| 1870 | 2354 | copied = 0; |
|---|
| 1871 | 2355 | encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); |
|---|
| 1872 | 2356 | |
|---|
| 1873 | | - drm_connector_for_each_possible_encoder(connector, encoder, i) { |
|---|
| 2357 | + drm_connector_for_each_possible_encoder(connector, encoder) { |
|---|
| 1874 | 2358 | if (put_user(encoder->base.id, encoder_ptr + copied)) { |
|---|
| 1875 | 2359 | ret = -EFAULT; |
|---|
| 1876 | 2360 | goto out; |
|---|
| .. | .. |
|---|
| 1897 | 2381 | out_resp->connection = connector->status; |
|---|
| 1898 | 2382 | |
|---|
| 1899 | 2383 | /* delayed so we get modes regardless of pre-fill_modes state */ |
|---|
| 1900 | | - list_for_each_entry(mode, &connector->modes, head) |
|---|
| 1901 | | - if (drm_mode_expose_to_userspace(mode, &export_list, |
|---|
| 2384 | + list_for_each_entry(mode, &connector->modes, head) { |
|---|
| 2385 | + WARN_ON(mode->expose_to_userspace); |
|---|
| 2386 | + |
|---|
| 2387 | + if (drm_mode_expose_to_userspace(mode, &connector->modes, |
|---|
| 1902 | 2388 | file_priv)) { |
|---|
| 1903 | | - list_add_tail(&mode->export_head, &export_list); |
|---|
| 2389 | + mode->expose_to_userspace = true; |
|---|
| 1904 | 2390 | mode_count++; |
|---|
| 1905 | 2391 | } |
|---|
| 2392 | + } |
|---|
| 1906 | 2393 | |
|---|
| 1907 | 2394 | /* |
|---|
| 1908 | 2395 | * This ioctl is called twice, once to determine how much space is |
|---|
| 1909 | 2396 | * needed, and the 2nd time to fill it. |
|---|
| 1910 | | - * The modes that need to be exposed to the user are maintained in the |
|---|
| 1911 | | - * 'export_list'. When the ioctl is called first time to determine the, |
|---|
| 1912 | | - * space, the export_list gets filled, to find the no.of modes. In the |
|---|
| 1913 | | - * 2nd time, the user modes are filled, one by one from the export_list. |
|---|
| 1914 | 2397 | */ |
|---|
| 1915 | 2398 | if ((out_resp->count_modes >= mode_count) && mode_count) { |
|---|
| 1916 | 2399 | copied = 0; |
|---|
| 1917 | 2400 | mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; |
|---|
| 1918 | | - list_for_each_entry(mode, &export_list, export_head) { |
|---|
| 2401 | + list_for_each_entry(mode, &connector->modes, head) { |
|---|
| 2402 | + if (!mode->expose_to_userspace) |
|---|
| 2403 | + continue; |
|---|
| 2404 | + |
|---|
| 2405 | + /* Clear the tag for the next time around */ |
|---|
| 2406 | + mode->expose_to_userspace = false; |
|---|
| 2407 | + |
|---|
| 1919 | 2408 | drm_mode_convert_to_umode(&u_mode, mode); |
|---|
| 1920 | 2409 | /* |
|---|
| 1921 | 2410 | * Reset aspect ratio flags of user-mode, if modes with |
|---|
| .. | .. |
|---|
| 1926 | 2415 | if (copy_to_user(mode_ptr + copied, |
|---|
| 1927 | 2416 | &u_mode, sizeof(u_mode))) { |
|---|
| 1928 | 2417 | ret = -EFAULT; |
|---|
| 2418 | + |
|---|
| 2419 | + /* |
|---|
| 2420 | + * Clear the tag for the rest of |
|---|
| 2421 | + * the modes for the next time around. |
|---|
| 2422 | + */ |
|---|
| 2423 | + list_for_each_entry_continue(mode, &connector->modes, head) |
|---|
| 2424 | + mode->expose_to_userspace = false; |
|---|
| 2425 | + |
|---|
| 1929 | 2426 | mutex_unlock(&dev->mode_config.mutex); |
|---|
| 1930 | 2427 | |
|---|
| 1931 | 2428 | goto out; |
|---|
| 1932 | 2429 | } |
|---|
| 1933 | 2430 | copied++; |
|---|
| 1934 | 2431 | } |
|---|
| 2432 | + } else { |
|---|
| 2433 | + /* Clear the tag for the next time around */ |
|---|
| 2434 | + list_for_each_entry(mode, &connector->modes, head) |
|---|
| 2435 | + mode->expose_to_userspace = false; |
|---|
| 1935 | 2436 | } |
|---|
| 2437 | + |
|---|
| 1936 | 2438 | out_resp->count_modes = mode_count; |
|---|
| 1937 | 2439 | mutex_unlock(&dev->mode_config.mutex); |
|---|
| 1938 | 2440 | |
|---|
| .. | .. |
|---|
| 1974 | 2476 | { |
|---|
| 1975 | 2477 | struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount); |
|---|
| 1976 | 2478 | struct drm_device *dev = tg->dev; |
|---|
| 2479 | + |
|---|
| 1977 | 2480 | mutex_lock(&dev->mode_config.idr_mutex); |
|---|
| 1978 | 2481 | idr_remove(&dev->mode_config.tile_idr, tg->id); |
|---|
| 1979 | 2482 | mutex_unlock(&dev->mode_config.idr_mutex); |
|---|
| .. | .. |
|---|
| 2005 | 2508 | * tile group or NULL if not found. |
|---|
| 2006 | 2509 | */ |
|---|
| 2007 | 2510 | struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, |
|---|
| 2008 | | - char topology[8]) |
|---|
| 2511 | + const char topology[8]) |
|---|
| 2009 | 2512 | { |
|---|
| 2010 | 2513 | struct drm_tile_group *tg; |
|---|
| 2011 | 2514 | int id; |
|---|
| 2515 | + |
|---|
| 2012 | 2516 | mutex_lock(&dev->mode_config.idr_mutex); |
|---|
| 2013 | 2517 | idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) { |
|---|
| 2014 | 2518 | if (!memcmp(tg->group_data, topology, 8)) { |
|---|
| .. | .. |
|---|
| 2032 | 2536 | * identifier for the tile group. |
|---|
| 2033 | 2537 | * |
|---|
| 2034 | 2538 | * RETURNS: |
|---|
| 2035 | | - * new tile group or error. |
|---|
| 2539 | + * new tile group or NULL. |
|---|
| 2036 | 2540 | */ |
|---|
| 2037 | 2541 | struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, |
|---|
| 2038 | | - char topology[8]) |
|---|
| 2542 | + const char topology[8]) |
|---|
| 2039 | 2543 | { |
|---|
| 2040 | 2544 | struct drm_tile_group *tg; |
|---|
| 2041 | 2545 | int ret; |
|---|
| 2042 | 2546 | |
|---|
| 2043 | 2547 | tg = kzalloc(sizeof(*tg), GFP_KERNEL); |
|---|
| 2044 | 2548 | if (!tg) |
|---|
| 2045 | | - return ERR_PTR(-ENOMEM); |
|---|
| 2549 | + return NULL; |
|---|
| 2046 | 2550 | |
|---|
| 2047 | 2551 | kref_init(&tg->refcount); |
|---|
| 2048 | 2552 | memcpy(tg->group_data, topology, 8); |
|---|
| .. | .. |
|---|
| 2054 | 2558 | tg->id = ret; |
|---|
| 2055 | 2559 | } else { |
|---|
| 2056 | 2560 | kfree(tg); |
|---|
| 2057 | | - tg = ERR_PTR(ret); |
|---|
| 2561 | + tg = NULL; |
|---|
| 2058 | 2562 | } |
|---|
| 2059 | 2563 | |
|---|
| 2060 | 2564 | mutex_unlock(&dev->mode_config.idr_mutex); |
|---|