| .. | .. |
|---|
| 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 | |
|---|
| .. | .. |
|---|
| 432 | 484 | mutex_destroy(&connector->mutex); |
|---|
| 433 | 485 | |
|---|
| 434 | 486 | memset(connector, 0, sizeof(*connector)); |
|---|
| 487 | + |
|---|
| 488 | + if (dev->registered) |
|---|
| 489 | + drm_sysfs_hotplug_event(dev); |
|---|
| 435 | 490 | } |
|---|
| 436 | 491 | EXPORT_SYMBOL(drm_connector_cleanup); |
|---|
| 437 | 492 | |
|---|
| .. | .. |
|---|
| 439 | 494 | * drm_connector_register - register a connector |
|---|
| 440 | 495 | * @connector: the connector to register |
|---|
| 441 | 496 | * |
|---|
| 442 | | - * Register userspace interfaces for a connector |
|---|
| 497 | + * Register userspace interfaces for a connector. Only call this for connectors |
|---|
| 498 | + * which can be hotplugged after drm_dev_register() has been called already, |
|---|
| 499 | + * e.g. DP MST connectors. All other connectors will be registered automatically |
|---|
| 500 | + * when calling drm_dev_register(). |
|---|
| 443 | 501 | * |
|---|
| 444 | 502 | * Returns: |
|---|
| 445 | 503 | * Zero on success, error code on failure. |
|---|
| .. | .. |
|---|
| 459 | 517 | if (ret) |
|---|
| 460 | 518 | goto unlock; |
|---|
| 461 | 519 | |
|---|
| 462 | | - ret = drm_debugfs_connector_add(connector); |
|---|
| 463 | | - if (ret) { |
|---|
| 464 | | - goto err_sysfs; |
|---|
| 465 | | - } |
|---|
| 520 | + drm_debugfs_connector_add(connector); |
|---|
| 466 | 521 | |
|---|
| 467 | 522 | if (connector->funcs->late_register) { |
|---|
| 468 | 523 | ret = connector->funcs->late_register(connector); |
|---|
| .. | .. |
|---|
| 473 | 528 | drm_mode_object_register(connector->dev, &connector->base); |
|---|
| 474 | 529 | |
|---|
| 475 | 530 | connector->registration_state = DRM_CONNECTOR_REGISTERED; |
|---|
| 531 | + |
|---|
| 532 | + /* Let userspace know we have a new connector */ |
|---|
| 533 | + drm_sysfs_hotplug_event(connector->dev); |
|---|
| 534 | + |
|---|
| 476 | 535 | goto unlock; |
|---|
| 477 | 536 | |
|---|
| 478 | 537 | err_debugfs: |
|---|
| 479 | 538 | drm_debugfs_connector_remove(connector); |
|---|
| 480 | | -err_sysfs: |
|---|
| 481 | 539 | drm_sysfs_connector_remove(connector); |
|---|
| 482 | 540 | unlock: |
|---|
| 483 | 541 | mutex_unlock(&connector->mutex); |
|---|
| .. | .. |
|---|
| 489 | 547 | * drm_connector_unregister - unregister a connector |
|---|
| 490 | 548 | * @connector: the connector to unregister |
|---|
| 491 | 549 | * |
|---|
| 492 | | - * Unregister userspace interfaces for a connector |
|---|
| 550 | + * Unregister userspace interfaces for a connector. Only call this for |
|---|
| 551 | + * connectors which have registered explicitly by calling drm_dev_register(), |
|---|
| 552 | + * since connectors are unregistered automatically when drm_dev_unregister() is |
|---|
| 553 | + * called. |
|---|
| 493 | 554 | */ |
|---|
| 494 | 555 | void drm_connector_unregister(struct drm_connector *connector) |
|---|
| 495 | 556 | { |
|---|
| .. | .. |
|---|
| 682 | 743 | __drm_connector_put_safe(iter->conn); |
|---|
| 683 | 744 | spin_unlock_irqrestore(&config->connector_list_lock, flags); |
|---|
| 684 | 745 | } |
|---|
| 685 | | - lock_release(&connector_list_iter_dep_map, 0, _RET_IP_); |
|---|
| 746 | + lock_release(&connector_list_iter_dep_map, _RET_IP_); |
|---|
| 686 | 747 | } |
|---|
| 687 | 748 | EXPORT_SYMBOL(drm_connector_list_iter_end); |
|---|
| 688 | 749 | |
|---|
| .. | .. |
|---|
| 792 | 853 | DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) |
|---|
| 793 | 854 | |
|---|
| 794 | 855 | static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = { |
|---|
| 795 | | - { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ |
|---|
| 856 | + { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */ |
|---|
| 796 | 857 | { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ |
|---|
| 797 | 858 | { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ |
|---|
| 798 | 859 | }; |
|---|
| .. | .. |
|---|
| 809 | 870 | DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) |
|---|
| 810 | 871 | |
|---|
| 811 | 872 | static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { |
|---|
| 812 | | - { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ |
|---|
| 873 | + { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */ |
|---|
| 813 | 874 | { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ |
|---|
| 814 | 875 | { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ |
|---|
| 815 | 876 | { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ |
|---|
| .. | .. |
|---|
| 818 | 879 | DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, |
|---|
| 819 | 880 | drm_tv_subconnector_enum_list) |
|---|
| 820 | 881 | |
|---|
| 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" }, |
|---|
| 882 | +static const struct drm_prop_enum_list drm_dp_subconnector_enum_list[] = { |
|---|
| 883 | + { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */ |
|---|
| 884 | + { DRM_MODE_SUBCONNECTOR_VGA, "VGA" }, /* DP */ |
|---|
| 885 | + { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DP */ |
|---|
| 886 | + { DRM_MODE_SUBCONNECTOR_HDMIA, "HDMI" }, /* DP */ |
|---|
| 887 | + { DRM_MODE_SUBCONNECTOR_DisplayPort, "DP" }, /* DP */ |
|---|
| 888 | + { DRM_MODE_SUBCONNECTOR_Wireless, "Wireless" }, /* DP */ |
|---|
| 889 | + { DRM_MODE_SUBCONNECTOR_Native, "Native" }, /* DP */ |
|---|
| 825 | 890 | }; |
|---|
| 826 | | -DRM_ENUM_NAME_FN(drm_get_content_protection_name, drm_cp_enum_list) |
|---|
| 891 | + |
|---|
| 892 | +DRM_ENUM_NAME_FN(drm_get_dp_subconnector_name, |
|---|
| 893 | + drm_dp_subconnector_enum_list) |
|---|
| 827 | 894 | |
|---|
| 828 | 895 | static const struct drm_prop_enum_list hdmi_colorspaces[] = { |
|---|
| 829 | 896 | /* For Default case, driver will set the colorspace */ |
|---|
| .. | .. |
|---|
| 852 | 919 | { DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER, "DCI-P3_RGB_Theater" }, |
|---|
| 853 | 920 | }; |
|---|
| 854 | 921 | |
|---|
| 922 | +/* |
|---|
| 923 | + * As per DP 1.4a spec, 2.2.5.7.5 VSC SDP Payload for Pixel Encoding/Colorimetry |
|---|
| 924 | + * Format Table 2-120 |
|---|
| 925 | + */ |
|---|
| 855 | 926 | static const struct drm_prop_enum_list dp_colorspaces[] = { |
|---|
| 856 | 927 | /* For Default case, driver will set the colorspace */ |
|---|
| 857 | 928 | { DRM_MODE_COLORIMETRY_DEFAULT, "Default" }, |
|---|
| 929 | + { DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED, "RGB_Wide_Gamut_Fixed_Point" }, |
|---|
| 930 | + /* Colorimetry based on scRGB (IEC 61966-2-2) */ |
|---|
| 931 | + { DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT, "RGB_Wide_Gamut_Floating_Point" }, |
|---|
| 932 | + /* Colorimetry based on IEC 61966-2-5 */ |
|---|
| 933 | + { DRM_MODE_COLORIMETRY_OPRGB, "opRGB" }, |
|---|
| 934 | + /* Colorimetry based on SMPTE RP 431-2 */ |
|---|
| 935 | + { DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65, "DCI-P3_RGB_D65" }, |
|---|
| 936 | + /* Colorimetry based on ITU-R BT.2020 */ |
|---|
| 937 | + { DRM_MODE_COLORIMETRY_BT2020_RGB, "BT2020_RGB" }, |
|---|
| 938 | + { DRM_MODE_COLORIMETRY_BT601_YCC, "BT601_YCC" }, |
|---|
| 939 | + { DRM_MODE_COLORIMETRY_BT709_YCC, "BT709_YCC" }, |
|---|
| 858 | 940 | /* Standard Definition Colorimetry based on IEC 61966-2-4 */ |
|---|
| 859 | 941 | { DRM_MODE_COLORIMETRY_XVYCC_601, "XVYCC_601" }, |
|---|
| 860 | 942 | /* High Definition Colorimetry based on IEC 61966-2-4 */ |
|---|
| 861 | 943 | { 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" }, |
|---|
| 944 | + /* Colorimetry based on IEC 61966-2-1/Amendment 1 */ |
|---|
| 945 | + { DRM_MODE_COLORIMETRY_SYCC_601, "SYCC_601" }, |
|---|
| 946 | + /* Colorimetry based on IEC 61966-2-5 [33] */ |
|---|
| 947 | + { DRM_MODE_COLORIMETRY_OPYCC_601, "opYCC_601" }, |
|---|
| 871 | 948 | /* Colorimetry based on ITU-R BT.2020 */ |
|---|
| 872 | | - { DRM_MODE_COLORIMETRY_BT2020_RGB, "BT2020_RGB" }, |
|---|
| 949 | + { DRM_MODE_COLORIMETRY_BT2020_CYCC, "BT2020_CYCC" }, |
|---|
| 873 | 950 | /* Colorimetry based on ITU-R BT.2020 */ |
|---|
| 874 | 951 | { DRM_MODE_COLORIMETRY_BT2020_YCC, "BT2020_YCC" }, |
|---|
| 875 | 952 | }; |
|---|
| .. | .. |
|---|
| 893 | 970 | * connector is linked to. Drivers should never set this property directly, |
|---|
| 894 | 971 | * it is handled by the DRM core by calling the &drm_connector_funcs.dpms |
|---|
| 895 | 972 | * 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. |
|---|
| 973 | + * implemented in the DRM core. |
|---|
| 898 | 974 | * |
|---|
| 899 | 975 | * Note that this property cannot be set through the MODE_ATOMIC ioctl, |
|---|
| 900 | 976 | * userspace must use "ACTIVE" on the CRTC instead. |
|---|
| .. | .. |
|---|
| 931 | 1007 | * DP MST sinks), or high-res integrated panels (like dual-link DSI) which |
|---|
| 932 | 1008 | * are not gen-locked. Note that for tiled panels which are genlocked, like |
|---|
| 933 | 1009 | * 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 |
|---|
| 1010 | + * tiling and virtualise both &drm_crtc and &drm_plane if needed. Drivers |
|---|
| 935 | 1011 | * should update this value using drm_connector_set_tile_property(). |
|---|
| 936 | 1012 | * Userspace cannot change this property. |
|---|
| 937 | 1013 | * link-status: |
|---|
| .. | .. |
|---|
| 940 | 1016 | * after modeset, the kernel driver may set this to "BAD" and issue a |
|---|
| 941 | 1017 | * hotplug uevent. Drivers should update this value using |
|---|
| 942 | 1018 | * drm_connector_set_link_status_property(). |
|---|
| 1019 | + * |
|---|
| 1020 | + * When user-space receives the hotplug uevent and detects a "BAD" |
|---|
| 1021 | + * link-status, the sink doesn't receive pixels anymore (e.g. the screen |
|---|
| 1022 | + * becomes completely black). The list of available modes may have |
|---|
| 1023 | + * changed. User-space is expected to pick a new mode if the current one |
|---|
| 1024 | + * has disappeared and perform a new modeset with link-status set to |
|---|
| 1025 | + * "GOOD" to re-enable the connector. |
|---|
| 1026 | + * |
|---|
| 1027 | + * If multiple connectors share the same CRTC and one of them gets a "BAD" |
|---|
| 1028 | + * link-status, the other are unaffected (ie. the sinks still continue to |
|---|
| 1029 | + * receive pixels). |
|---|
| 1030 | + * |
|---|
| 1031 | + * When user-space performs an atomic commit on a connector with a "BAD" |
|---|
| 1032 | + * link-status without resetting the property to "GOOD", the sink may |
|---|
| 1033 | + * still not receive pixels. When user-space performs an atomic commit |
|---|
| 1034 | + * which resets the link-status property to "GOOD" without the |
|---|
| 1035 | + * ALLOW_MODESET flag set, it might fail because a modeset is required. |
|---|
| 1036 | + * |
|---|
| 1037 | + * User-space can only change link-status to "GOOD", changing it to "BAD" |
|---|
| 1038 | + * is a no-op. |
|---|
| 1039 | + * |
|---|
| 1040 | + * For backwards compatibility with non-atomic userspace the kernel |
|---|
| 1041 | + * tries to automatically set the link-status back to "GOOD" in the |
|---|
| 1042 | + * SETCRTC IOCTL. This might fail if the mode is no longer valid, similar |
|---|
| 1043 | + * to how it might fail if a different screen has been connected in the |
|---|
| 1044 | + * interim. |
|---|
| 943 | 1045 | * non_desktop: |
|---|
| 944 | 1046 | * Indicates the output should be ignored for purposes of displaying a |
|---|
| 945 | 1047 | * standard desktop environment or console. This is most likely because |
|---|
| .. | .. |
|---|
| 975 | 1077 | * - If the state is DESIRED, kernel should attempt to re-authenticate the |
|---|
| 976 | 1078 | * link whenever possible. This includes across disable/enable, dpms, |
|---|
| 977 | 1079 | * 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). |
|---|
| 1080 | + * - Kernel sends uevent with the connector id and property id through |
|---|
| 1081 | + * @drm_hdcp_update_content_protection, upon below kernel triggered |
|---|
| 1082 | + * scenarios: |
|---|
| 1083 | + * |
|---|
| 1084 | + * - DESIRED -> ENABLED (authentication success) |
|---|
| 1085 | + * - ENABLED -> DESIRED (termination of authentication) |
|---|
| 1086 | + * - Please note no uevents for userspace triggered property state changes, |
|---|
| 1087 | + * which can't fail such as |
|---|
| 1088 | + * |
|---|
| 1089 | + * - DESIRED/ENABLED -> UNDESIRED |
|---|
| 1090 | + * - UNDESIRED -> DESIRED |
|---|
| 1091 | + * - Userspace is responsible for polling the property or listen to uevents |
|---|
| 1092 | + * to determine when the value transitions from ENABLED to DESIRED. |
|---|
| 1093 | + * This signifies the link is no longer protected and userspace should |
|---|
| 1094 | + * take appropriate action (whatever that might be). |
|---|
| 1095 | + * |
|---|
| 1096 | + * HDCP Content Type: |
|---|
| 1097 | + * This Enum property is used by the userspace to declare the content type |
|---|
| 1098 | + * of the display stream, to kernel. Here display stream stands for any |
|---|
| 1099 | + * display content that userspace intended to display through HDCP |
|---|
| 1100 | + * encryption. |
|---|
| 1101 | + * |
|---|
| 1102 | + * Content Type of a stream is decided by the owner of the stream, as |
|---|
| 1103 | + * "HDCP Type0" or "HDCP Type1". |
|---|
| 1104 | + * |
|---|
| 1105 | + * The value of the property can be one of the below: |
|---|
| 1106 | + * - "HDCP Type0": DRM_MODE_HDCP_CONTENT_TYPE0 = 0 |
|---|
| 1107 | + * - "HDCP Type1": DRM_MODE_HDCP_CONTENT_TYPE1 = 1 |
|---|
| 1108 | + * |
|---|
| 1109 | + * When kernel starts the HDCP authentication (see "Content Protection" |
|---|
| 1110 | + * for details), it uses the content type in "HDCP Content Type" |
|---|
| 1111 | + * for performing the HDCP authentication with the display sink. |
|---|
| 1112 | + * |
|---|
| 1113 | + * Please note in HDCP spec versions, a link can be authenticated with |
|---|
| 1114 | + * HDCP 2.2 for Content Type 0/Content Type 1. Where as a link can be |
|---|
| 1115 | + * authenticated with HDCP1.4 only for Content Type 0(though it is implicit |
|---|
| 1116 | + * in nature. As there is no reference for Content Type in HDCP1.4). |
|---|
| 1117 | + * |
|---|
| 1118 | + * HDCP2.2 authentication protocol itself takes the "Content Type" as a |
|---|
| 1119 | + * parameter, which is a input for the DP HDCP2.2 encryption algo. |
|---|
| 1120 | + * |
|---|
| 1121 | + * In case of Type 0 content protection request, kernel driver can choose |
|---|
| 1122 | + * either of HDCP spec versions 1.4 and 2.2. When HDCP2.2 is used for |
|---|
| 1123 | + * "HDCP Type 0", a HDCP 2.2 capable repeater in the downstream can send |
|---|
| 1124 | + * that content to a HDCP 1.4 authenticated HDCP sink (Type0 link). |
|---|
| 1125 | + * But if the content is classified as "HDCP Type 1", above mentioned |
|---|
| 1126 | + * HDCP 2.2 repeater wont send the content to the HDCP sink as it can't |
|---|
| 1127 | + * authenticate the HDCP1.4 capable sink for "HDCP Type 1". |
|---|
| 1128 | + * |
|---|
| 1129 | + * Please note userspace can be ignorant of the HDCP versions used by the |
|---|
| 1130 | + * kernel driver to achieve the "HDCP Content Type". |
|---|
| 1131 | + * |
|---|
| 1132 | + * At current scenario, classifying a content as Type 1 ensures that the |
|---|
| 1133 | + * content will be displayed only through the HDCP2.2 encrypted link. |
|---|
| 1134 | + * |
|---|
| 1135 | + * Note that the HDCP Content Type property is introduced at HDCP 2.2, and |
|---|
| 1136 | + * defaults to type 0. It is only exposed by drivers supporting HDCP 2.2 |
|---|
| 1137 | + * (hence supporting Type 0 and Type 1). Based on how next versions of |
|---|
| 1138 | + * HDCP specs are defined content Type could be used for higher versions |
|---|
| 1139 | + * too. |
|---|
| 1140 | + * |
|---|
| 1141 | + * If content type is changed when "Content Protection" is not UNDESIRED, |
|---|
| 1142 | + * then kernel will disable the HDCP and re-enable with new type in the |
|---|
| 1143 | + * same atomic commit. And when "Content Protection" is ENABLED, it means |
|---|
| 1144 | + * that link is HDCP authenticated and encrypted, for the transmission of |
|---|
| 1145 | + * the Type of stream mentioned at "HDCP Content Type". |
|---|
| 1146 | + * |
|---|
| 1147 | + * HDR_OUTPUT_METADATA: |
|---|
| 1148 | + * Connector property to enable userspace to send HDR Metadata to |
|---|
| 1149 | + * driver. This metadata is based on the composition and blending |
|---|
| 1150 | + * policies decided by user, taking into account the hardware and |
|---|
| 1151 | + * sink capabilities. The driver gets this metadata and creates a |
|---|
| 1152 | + * Dynamic Range and Mastering Infoframe (DRM) in case of HDMI, |
|---|
| 1153 | + * SDP packet (Non-audio INFOFRAME SDP v1.3) for DP. This is then |
|---|
| 1154 | + * sent to sink. This notifies the sink of the upcoming frame's Color |
|---|
| 1155 | + * Encoding and Luminance parameters. |
|---|
| 1156 | + * |
|---|
| 1157 | + * Userspace first need to detect the HDR capabilities of sink by |
|---|
| 1158 | + * reading and parsing the EDID. Details of HDR metadata for HDMI |
|---|
| 1159 | + * are added in CTA 861.G spec. For DP , its defined in VESA DP |
|---|
| 1160 | + * Standard v1.4. It needs to then get the metadata information |
|---|
| 1161 | + * of the video/game/app content which are encoded in HDR (basically |
|---|
| 1162 | + * using HDR transfer functions). With this information it needs to |
|---|
| 1163 | + * decide on a blending policy and compose the relevant |
|---|
| 1164 | + * layers/overlays into a common format. Once this blending is done, |
|---|
| 1165 | + * userspace will be aware of the metadata of the composed frame to |
|---|
| 1166 | + * be send to sink. It then uses this property to communicate this |
|---|
| 1167 | + * metadata to driver which then make a Infoframe packet and sends |
|---|
| 1168 | + * to sink based on the type of encoder connected. |
|---|
| 1169 | + * |
|---|
| 1170 | + * Userspace will be responsible to do Tone mapping operation in case: |
|---|
| 1171 | + * - Some layers are HDR and others are SDR |
|---|
| 1172 | + * - HDR layers luminance is not same as sink |
|---|
| 1173 | + * |
|---|
| 1174 | + * It will even need to do colorspace conversion and get all layers |
|---|
| 1175 | + * to one common colorspace for blending. It can use either GL, Media |
|---|
| 1176 | + * or display engine to get this done based on the capabilities of the |
|---|
| 1177 | + * associated hardware. |
|---|
| 1178 | + * |
|---|
| 1179 | + * Driver expects metadata to be put in &struct hdr_output_metadata |
|---|
| 1180 | + * structure from userspace. This is received as blob and stored in |
|---|
| 1181 | + * &drm_connector_state.hdr_output_metadata. It parses EDID and saves the |
|---|
| 1182 | + * sink metadata in &struct hdr_sink_metadata, as |
|---|
| 1183 | + * &drm_connector.hdr_sink_metadata. Driver uses |
|---|
| 1184 | + * drm_hdmi_infoframe_set_hdr_metadata() helper to set the HDR metadata, |
|---|
| 1185 | + * hdmi_drm_infoframe_pack() to pack the infoframe as per spec, in case of |
|---|
| 1186 | + * HDMI encoder. |
|---|
| 1187 | + * |
|---|
| 1188 | + * max bpc: |
|---|
| 1189 | + * This range property is used by userspace to limit the bit depth. When |
|---|
| 1190 | + * used the driver would limit the bpc in accordance with the valid range |
|---|
| 1191 | + * supported by the hardware and sink. Drivers to use the function |
|---|
| 1192 | + * drm_connector_attach_max_bpc_property() to create and attach the |
|---|
| 1193 | + * property to the connector during initialization. |
|---|
| 982 | 1194 | * |
|---|
| 983 | 1195 | * Connectors also have one standardized atomic property: |
|---|
| 984 | 1196 | * |
|---|
| .. | .. |
|---|
| 996 | 1208 | * coordinates, so if userspace rotates the picture to adjust for |
|---|
| 997 | 1209 | * the orientation it must also apply the same transformation to the |
|---|
| 998 | 1210 | * touchscreen input coordinates. This property is initialized by calling |
|---|
| 999 | | - * drm_connector_init_panel_orientation_property(). |
|---|
| 1211 | + * drm_connector_set_panel_orientation() or |
|---|
| 1212 | + * drm_connector_set_panel_orientation_with_quirk() |
|---|
| 1000 | 1213 | * |
|---|
| 1001 | 1214 | * scaling mode: |
|---|
| 1002 | 1215 | * This property defines how a non-native mode is upscaled to the native |
|---|
| .. | .. |
|---|
| 1020 | 1233 | * can also expose this property to external outputs, in which case they |
|---|
| 1021 | 1234 | * must support "None", which should be the default (since external screens |
|---|
| 1022 | 1235 | * have a built-in scaler). |
|---|
| 1236 | + * |
|---|
| 1237 | + * subconnector: |
|---|
| 1238 | + * This property is used by DVI-I, TVout and DisplayPort to indicate different |
|---|
| 1239 | + * connector subtypes. Enum values more or less match with those from main |
|---|
| 1240 | + * connector types. |
|---|
| 1241 | + * For DVI-I and TVout there is also a matching property "select subconnector" |
|---|
| 1242 | + * allowing to switch between signal types. |
|---|
| 1243 | + * DP subconnector corresponds to a downstream port. |
|---|
| 1023 | 1244 | */ |
|---|
| 1024 | 1245 | |
|---|
| 1025 | 1246 | int drm_connector_create_standard_properties(struct drm_device *dev) |
|---|
| .. | .. |
|---|
| 1109 | 1330 | EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); |
|---|
| 1110 | 1331 | |
|---|
| 1111 | 1332 | /** |
|---|
| 1333 | + * drm_connector_attach_dp_subconnector_property - create subconnector property for DP |
|---|
| 1334 | + * @connector: drm_connector to attach property |
|---|
| 1335 | + * |
|---|
| 1336 | + * Called by a driver when DP connector is created. |
|---|
| 1337 | + */ |
|---|
| 1338 | +void drm_connector_attach_dp_subconnector_property(struct drm_connector *connector) |
|---|
| 1339 | +{ |
|---|
| 1340 | + struct drm_mode_config *mode_config = &connector->dev->mode_config; |
|---|
| 1341 | + |
|---|
| 1342 | + if (!mode_config->dp_subconnector_property) |
|---|
| 1343 | + mode_config->dp_subconnector_property = |
|---|
| 1344 | + drm_property_create_enum(connector->dev, |
|---|
| 1345 | + DRM_MODE_PROP_IMMUTABLE, |
|---|
| 1346 | + "subconnector", |
|---|
| 1347 | + drm_dp_subconnector_enum_list, |
|---|
| 1348 | + ARRAY_SIZE(drm_dp_subconnector_enum_list)); |
|---|
| 1349 | + |
|---|
| 1350 | + drm_object_attach_property(&connector->base, |
|---|
| 1351 | + mode_config->dp_subconnector_property, |
|---|
| 1352 | + DRM_MODE_SUBCONNECTOR_Unknown); |
|---|
| 1353 | +} |
|---|
| 1354 | +EXPORT_SYMBOL(drm_connector_attach_dp_subconnector_property); |
|---|
| 1355 | + |
|---|
| 1356 | +/** |
|---|
| 1112 | 1357 | * DOC: HDMI connector properties |
|---|
| 1113 | 1358 | * |
|---|
| 1114 | 1359 | * content type (HDMI specific): |
|---|
| 1115 | 1360 | * 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 |
|---|
| 1361 | + * content type for the external device, so that it adjusts its display |
|---|
| 1117 | 1362 | * settings accordingly. |
|---|
| 1118 | 1363 | * |
|---|
| 1119 | 1364 | * The value of this property can be one of the following: |
|---|
| .. | .. |
|---|
| 1185 | 1430 | EXPORT_SYMBOL(drm_hdmi_avi_infoframe_content_type); |
|---|
| 1186 | 1431 | |
|---|
| 1187 | 1432 | /** |
|---|
| 1188 | | - * drm_create_tv_properties - create TV specific connector properties |
|---|
| 1433 | + * drm_mode_attach_tv_margin_properties - attach TV connector margin properties |
|---|
| 1434 | + * @connector: DRM connector |
|---|
| 1435 | + * |
|---|
| 1436 | + * Called by a driver when it needs to attach TV margin props to a connector. |
|---|
| 1437 | + * Typically used on SDTV and HDMI connectors. |
|---|
| 1438 | + */ |
|---|
| 1439 | +void drm_connector_attach_tv_margin_properties(struct drm_connector *connector) |
|---|
| 1440 | +{ |
|---|
| 1441 | + struct drm_device *dev = connector->dev; |
|---|
| 1442 | + |
|---|
| 1443 | + drm_object_attach_property(&connector->base, |
|---|
| 1444 | + dev->mode_config.tv_left_margin_property, |
|---|
| 1445 | + 0); |
|---|
| 1446 | + drm_object_attach_property(&connector->base, |
|---|
| 1447 | + dev->mode_config.tv_right_margin_property, |
|---|
| 1448 | + 0); |
|---|
| 1449 | + drm_object_attach_property(&connector->base, |
|---|
| 1450 | + dev->mode_config.tv_top_margin_property, |
|---|
| 1451 | + 0); |
|---|
| 1452 | + drm_object_attach_property(&connector->base, |
|---|
| 1453 | + dev->mode_config.tv_bottom_margin_property, |
|---|
| 1454 | + 0); |
|---|
| 1455 | +} |
|---|
| 1456 | +EXPORT_SYMBOL(drm_connector_attach_tv_margin_properties); |
|---|
| 1457 | + |
|---|
| 1458 | +/** |
|---|
| 1459 | + * drm_mode_create_tv_margin_properties - create TV connector margin properties |
|---|
| 1460 | + * @dev: DRM device |
|---|
| 1461 | + * |
|---|
| 1462 | + * Called by a driver's HDMI connector initialization routine, this function |
|---|
| 1463 | + * creates the TV margin properties for a given device. No need to call this |
|---|
| 1464 | + * function for an SDTV connector, it's already called from |
|---|
| 1465 | + * drm_mode_create_tv_properties(). |
|---|
| 1466 | + */ |
|---|
| 1467 | +int drm_mode_create_tv_margin_properties(struct drm_device *dev) |
|---|
| 1468 | +{ |
|---|
| 1469 | + if (dev->mode_config.tv_left_margin_property) |
|---|
| 1470 | + return 0; |
|---|
| 1471 | + |
|---|
| 1472 | + dev->mode_config.tv_left_margin_property = |
|---|
| 1473 | + drm_property_create_range(dev, 0, "left margin", 0, 100); |
|---|
| 1474 | + if (!dev->mode_config.tv_left_margin_property) |
|---|
| 1475 | + return -ENOMEM; |
|---|
| 1476 | + |
|---|
| 1477 | + dev->mode_config.tv_right_margin_property = |
|---|
| 1478 | + drm_property_create_range(dev, 0, "right margin", 0, 100); |
|---|
| 1479 | + if (!dev->mode_config.tv_right_margin_property) |
|---|
| 1480 | + return -ENOMEM; |
|---|
| 1481 | + |
|---|
| 1482 | + dev->mode_config.tv_top_margin_property = |
|---|
| 1483 | + drm_property_create_range(dev, 0, "top margin", 0, 100); |
|---|
| 1484 | + if (!dev->mode_config.tv_top_margin_property) |
|---|
| 1485 | + return -ENOMEM; |
|---|
| 1486 | + |
|---|
| 1487 | + dev->mode_config.tv_bottom_margin_property = |
|---|
| 1488 | + drm_property_create_range(dev, 0, "bottom margin", 0, 100); |
|---|
| 1489 | + if (!dev->mode_config.tv_bottom_margin_property) |
|---|
| 1490 | + return -ENOMEM; |
|---|
| 1491 | + |
|---|
| 1492 | + return 0; |
|---|
| 1493 | +} |
|---|
| 1494 | +EXPORT_SYMBOL(drm_mode_create_tv_margin_properties); |
|---|
| 1495 | + |
|---|
| 1496 | +/** |
|---|
| 1497 | + * drm_mode_create_tv_properties - create TV specific connector properties |
|---|
| 1189 | 1498 | * @dev: DRM device |
|---|
| 1190 | 1499 | * @num_modes: number of different TV formats (modes) supported |
|---|
| 1191 | 1500 | * @modes: array of pointers to strings containing name of each format |
|---|
| .. | .. |
|---|
| 1230 | 1539 | /* |
|---|
| 1231 | 1540 | * Other, TV specific properties: margins & TV modes. |
|---|
| 1232 | 1541 | */ |
|---|
| 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) |
|---|
| 1542 | + if (drm_mode_create_tv_margin_properties(dev)) |
|---|
| 1251 | 1543 | goto nomem; |
|---|
| 1252 | 1544 | |
|---|
| 1253 | 1545 | dev->mode_config.tv_mode_property = |
|---|
| .. | .. |
|---|
| 1326 | 1618 | EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); |
|---|
| 1327 | 1619 | |
|---|
| 1328 | 1620 | /** |
|---|
| 1621 | + * DOC: Variable refresh properties |
|---|
| 1622 | + * |
|---|
| 1623 | + * Variable refresh rate capable displays can dynamically adjust their |
|---|
| 1624 | + * refresh rate by extending the duration of their vertical front porch |
|---|
| 1625 | + * until page flip or timeout occurs. This can reduce or remove stuttering |
|---|
| 1626 | + * and latency in scenarios where the page flip does not align with the |
|---|
| 1627 | + * vblank interval. |
|---|
| 1628 | + * |
|---|
| 1629 | + * An example scenario would be an application flipping at a constant rate |
|---|
| 1630 | + * of 48Hz on a 60Hz display. The page flip will frequently miss the vblank |
|---|
| 1631 | + * interval and the same contents will be displayed twice. This can be |
|---|
| 1632 | + * observed as stuttering for content with motion. |
|---|
| 1633 | + * |
|---|
| 1634 | + * If variable refresh rate was active on a display that supported a |
|---|
| 1635 | + * variable refresh range from 35Hz to 60Hz no stuttering would be observable |
|---|
| 1636 | + * for the example scenario. The minimum supported variable refresh rate of |
|---|
| 1637 | + * 35Hz is below the page flip frequency and the vertical front porch can |
|---|
| 1638 | + * be extended until the page flip occurs. The vblank interval will be |
|---|
| 1639 | + * directly aligned to the page flip rate. |
|---|
| 1640 | + * |
|---|
| 1641 | + * Not all userspace content is suitable for use with variable refresh rate. |
|---|
| 1642 | + * Large and frequent changes in vertical front porch duration may worsen |
|---|
| 1643 | + * perceived stuttering for input sensitive applications. |
|---|
| 1644 | + * |
|---|
| 1645 | + * Panel brightness will also vary with vertical front porch duration. Some |
|---|
| 1646 | + * panels may have noticeable differences in brightness between the minimum |
|---|
| 1647 | + * vertical front porch duration and the maximum vertical front porch duration. |
|---|
| 1648 | + * Large and frequent changes in vertical front porch duration may produce |
|---|
| 1649 | + * observable flickering for such panels. |
|---|
| 1650 | + * |
|---|
| 1651 | + * Userspace control for variable refresh rate is supported via properties |
|---|
| 1652 | + * on the &drm_connector and &drm_crtc objects. |
|---|
| 1653 | + * |
|---|
| 1654 | + * "vrr_capable": |
|---|
| 1655 | + * Optional &drm_connector boolean property that drivers should attach |
|---|
| 1656 | + * with drm_connector_attach_vrr_capable_property() on connectors that |
|---|
| 1657 | + * could support variable refresh rates. Drivers should update the |
|---|
| 1658 | + * property value by calling drm_connector_set_vrr_capable_property(). |
|---|
| 1659 | + * |
|---|
| 1660 | + * Absence of the property should indicate absence of support. |
|---|
| 1661 | + * |
|---|
| 1662 | + * "VRR_ENABLED": |
|---|
| 1663 | + * Default &drm_crtc boolean property that notifies the driver that the |
|---|
| 1664 | + * content on the CRTC is suitable for variable refresh rate presentation. |
|---|
| 1665 | + * The driver will take this property as a hint to enable variable |
|---|
| 1666 | + * refresh rate support if the receiver supports it, ie. if the |
|---|
| 1667 | + * "vrr_capable" property is true on the &drm_connector object. The |
|---|
| 1668 | + * vertical front porch duration will be extended until page-flip or |
|---|
| 1669 | + * timeout when enabled. |
|---|
| 1670 | + * |
|---|
| 1671 | + * The minimum vertical front porch duration is defined as the vertical |
|---|
| 1672 | + * front porch duration for the current mode. |
|---|
| 1673 | + * |
|---|
| 1674 | + * The maximum vertical front porch duration is greater than or equal to |
|---|
| 1675 | + * the minimum vertical front porch duration. The duration is derived |
|---|
| 1676 | + * from the minimum supported variable refresh rate for the connector. |
|---|
| 1677 | + * |
|---|
| 1678 | + * The driver may place further restrictions within these minimum |
|---|
| 1679 | + * and maximum bounds. |
|---|
| 1680 | + */ |
|---|
| 1681 | + |
|---|
| 1682 | +/** |
|---|
| 1683 | + * drm_connector_attach_vrr_capable_property - creates the |
|---|
| 1684 | + * vrr_capable property |
|---|
| 1685 | + * @connector: connector to create the vrr_capable property on. |
|---|
| 1686 | + * |
|---|
| 1687 | + * This is used by atomic drivers to add support for querying |
|---|
| 1688 | + * variable refresh rate capability for a connector. |
|---|
| 1689 | + * |
|---|
| 1690 | + * Returns: |
|---|
| 1691 | + * Zero on success, negative errno on failure. |
|---|
| 1692 | + */ |
|---|
| 1693 | +int drm_connector_attach_vrr_capable_property( |
|---|
| 1694 | + struct drm_connector *connector) |
|---|
| 1695 | +{ |
|---|
| 1696 | + struct drm_device *dev = connector->dev; |
|---|
| 1697 | + struct drm_property *prop; |
|---|
| 1698 | + |
|---|
| 1699 | + if (!connector->vrr_capable_property) { |
|---|
| 1700 | + prop = drm_property_create_bool(dev, DRM_MODE_PROP_IMMUTABLE, |
|---|
| 1701 | + "vrr_capable"); |
|---|
| 1702 | + if (!prop) |
|---|
| 1703 | + return -ENOMEM; |
|---|
| 1704 | + |
|---|
| 1705 | + connector->vrr_capable_property = prop; |
|---|
| 1706 | + drm_object_attach_property(&connector->base, prop, 0); |
|---|
| 1707 | + } |
|---|
| 1708 | + |
|---|
| 1709 | + return 0; |
|---|
| 1710 | +} |
|---|
| 1711 | +EXPORT_SYMBOL(drm_connector_attach_vrr_capable_property); |
|---|
| 1712 | + |
|---|
| 1713 | +/** |
|---|
| 1329 | 1714 | * drm_connector_attach_scaling_mode_property - attach atomic scaling mode property |
|---|
| 1330 | 1715 | * @connector: connector to attach scaling mode property on. |
|---|
| 1331 | 1716 | * @scaling_mode_mask: or'ed mask of BIT(%DRM_MODE_SCALE_\*). |
|---|
| .. | .. |
|---|
| 1386 | 1771 | EXPORT_SYMBOL(drm_connector_attach_scaling_mode_property); |
|---|
| 1387 | 1772 | |
|---|
| 1388 | 1773 | /** |
|---|
| 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 | 1774 | * drm_mode_create_aspect_ratio_property - create aspect ratio property |
|---|
| 1426 | 1775 | * @dev: DRM device |
|---|
| 1427 | 1776 | * |
|---|
| .. | .. |
|---|
| 1452 | 1801 | * DOC: standard connector properties |
|---|
| 1453 | 1802 | * |
|---|
| 1454 | 1803 | * Colorspace: |
|---|
| 1455 | | - * drm_mode_create_colorspace_property - create colorspace property |
|---|
| 1456 | 1804 | * This property helps select a suitable colorspace based on the sink |
|---|
| 1457 | 1805 | * capability. Modern sink devices support wider gamut like BT2020. |
|---|
| 1458 | 1806 | * This helps switch to BT2020 mode if the BT2020 encoded video stream |
|---|
| .. | .. |
|---|
| 1472 | 1820 | * - This property is just to inform sink what colorspace |
|---|
| 1473 | 1821 | * source is trying to drive. |
|---|
| 1474 | 1822 | * |
|---|
| 1475 | | - * Called by a driver the first time it's needed, must be attached to desired |
|---|
| 1476 | | - * connectors. |
|---|
| 1823 | + * Because between HDMI and DP have different colorspaces, |
|---|
| 1824 | + * drm_mode_create_hdmi_colorspace_property() is used for HDMI connector and |
|---|
| 1825 | + * drm_mode_create_dp_colorspace_property() is used for DP connector. |
|---|
| 1477 | 1826 | */ |
|---|
| 1478 | | -int drm_mode_create_colorspace_property(struct drm_connector *connector) |
|---|
| 1827 | + |
|---|
| 1828 | +/** |
|---|
| 1829 | + * drm_mode_create_hdmi_colorspace_property - create hdmi colorspace property |
|---|
| 1830 | + * @connector: connector to create the Colorspace property on. |
|---|
| 1831 | + * |
|---|
| 1832 | + * Called by a driver the first time it's needed, must be attached to desired |
|---|
| 1833 | + * HDMI connectors. |
|---|
| 1834 | + * |
|---|
| 1835 | + * Returns: |
|---|
| 1836 | + * Zero on success, negative errno on failure. |
|---|
| 1837 | + */ |
|---|
| 1838 | +int drm_mode_create_hdmi_colorspace_property(struct drm_connector *connector) |
|---|
| 1479 | 1839 | { |
|---|
| 1480 | 1840 | struct drm_device *dev = connector->dev; |
|---|
| 1481 | | - struct drm_property *prop; |
|---|
| 1482 | 1841 | |
|---|
| 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"); |
|---|
| 1842 | + if (connector->colorspace_property) |
|---|
| 1501 | 1843 | return 0; |
|---|
| 1502 | | - } |
|---|
| 1503 | 1844 | |
|---|
| 1504 | | - connector->colorspace_property = prop; |
|---|
| 1845 | + connector->colorspace_property = |
|---|
| 1846 | + drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "Colorspace", |
|---|
| 1847 | + hdmi_colorspaces, |
|---|
| 1848 | + ARRAY_SIZE(hdmi_colorspaces)); |
|---|
| 1849 | + |
|---|
| 1850 | + if (!connector->colorspace_property) |
|---|
| 1851 | + return -ENOMEM; |
|---|
| 1505 | 1852 | |
|---|
| 1506 | 1853 | return 0; |
|---|
| 1507 | 1854 | } |
|---|
| 1508 | | -EXPORT_SYMBOL(drm_mode_create_colorspace_property); |
|---|
| 1855 | +EXPORT_SYMBOL(drm_mode_create_hdmi_colorspace_property); |
|---|
| 1856 | + |
|---|
| 1857 | +/** |
|---|
| 1858 | + * drm_mode_create_dp_colorspace_property - create dp colorspace property |
|---|
| 1859 | + * @connector: connector to create the Colorspace property on. |
|---|
| 1860 | + * |
|---|
| 1861 | + * Called by a driver the first time it's needed, must be attached to desired |
|---|
| 1862 | + * DP connectors. |
|---|
| 1863 | + * |
|---|
| 1864 | + * Returns: |
|---|
| 1865 | + * Zero on success, negative errno on failure. |
|---|
| 1866 | + */ |
|---|
| 1867 | +int drm_mode_create_dp_colorspace_property(struct drm_connector *connector) |
|---|
| 1868 | +{ |
|---|
| 1869 | + struct drm_device *dev = connector->dev; |
|---|
| 1870 | + |
|---|
| 1871 | + if (connector->colorspace_property) |
|---|
| 1872 | + return 0; |
|---|
| 1873 | + |
|---|
| 1874 | + connector->colorspace_property = |
|---|
| 1875 | + drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "Colorspace", |
|---|
| 1876 | + dp_colorspaces, |
|---|
| 1877 | + ARRAY_SIZE(dp_colorspaces)); |
|---|
| 1878 | + |
|---|
| 1879 | + if (!connector->colorspace_property) |
|---|
| 1880 | + return -ENOMEM; |
|---|
| 1881 | + |
|---|
| 1882 | + return 0; |
|---|
| 1883 | +} |
|---|
| 1884 | +EXPORT_SYMBOL(drm_mode_create_dp_colorspace_property); |
|---|
| 1509 | 1885 | |
|---|
| 1510 | 1886 | /** |
|---|
| 1511 | 1887 | * drm_mode_create_content_type_property - create content type property |
|---|
| .. | .. |
|---|
| 1538 | 1914 | * drm_mode_create_suggested_offset_properties - create suggests offset properties |
|---|
| 1539 | 1915 | * @dev: DRM device |
|---|
| 1540 | 1916 | * |
|---|
| 1541 | | - * Create the the suggested x/y offset property for connectors. |
|---|
| 1917 | + * Create the suggested x/y offset property for connectors. |
|---|
| 1542 | 1918 | */ |
|---|
| 1543 | 1919 | int drm_mode_create_suggested_offset_properties(struct drm_device *dev) |
|---|
| 1544 | 1920 | { |
|---|
| .. | .. |
|---|
| 1594 | 1970 | * This looks up the tile information for a connector, and creates a |
|---|
| 1595 | 1971 | * property for userspace to parse if it exists. The property is of |
|---|
| 1596 | 1972 | * the form of 8 integers using ':' as a separator. |
|---|
| 1973 | + * This is used for dual port tiled displays with DisplayPort SST |
|---|
| 1974 | + * or DisplayPort MST connectors. |
|---|
| 1597 | 1975 | * |
|---|
| 1598 | 1976 | * Returns: |
|---|
| 1599 | 1977 | * Zero on success, errno on failure. |
|---|
| .. | .. |
|---|
| 1637 | 2015 | * |
|---|
| 1638 | 2016 | * This function creates a new blob modeset object and assigns its id to the |
|---|
| 1639 | 2017 | * connector's edid property. |
|---|
| 2018 | + * Since we also parse tile information from EDID's displayID block, we also |
|---|
| 2019 | + * set the connector's tile property here. See drm_connector_set_tile_property() |
|---|
| 2020 | + * for more details. |
|---|
| 1640 | 2021 | * |
|---|
| 1641 | 2022 | * Returns: |
|---|
| 1642 | 2023 | * Zero on success, negative errno on failure. |
|---|
| .. | .. |
|---|
| 1647 | 2028 | struct drm_device *dev = connector->dev; |
|---|
| 1648 | 2029 | size_t size = 0; |
|---|
| 1649 | 2030 | int ret; |
|---|
| 2031 | + const struct edid *old_edid; |
|---|
| 1650 | 2032 | |
|---|
| 1651 | 2033 | /* ignore requests to set edid when overridden */ |
|---|
| 1652 | 2034 | if (connector->override_edid) |
|---|
| .. | .. |
|---|
| 1656 | 2038 | size = EDID_LENGTH * (1 + edid->extensions); |
|---|
| 1657 | 2039 | |
|---|
| 1658 | 2040 | /* Set the display info, using edid if available, otherwise |
|---|
| 1659 | | - * reseting the values to defaults. This duplicates the work |
|---|
| 2041 | + * resetting the values to defaults. This duplicates the work |
|---|
| 1660 | 2042 | * done in drm_add_edid_modes, but that function is not |
|---|
| 1661 | 2043 | * consistently called before this one in all drivers and the |
|---|
| 1662 | 2044 | * computation is cheap enough that it seems better to |
|---|
| .. | .. |
|---|
| 1668 | 2050 | else |
|---|
| 1669 | 2051 | drm_reset_display_info(connector); |
|---|
| 1670 | 2052 | |
|---|
| 2053 | + drm_update_tile_info(connector, edid); |
|---|
| 2054 | + |
|---|
| 2055 | + if (connector->edid_blob_ptr) { |
|---|
| 2056 | + old_edid = (const struct edid *)connector->edid_blob_ptr->data; |
|---|
| 2057 | + if (old_edid) { |
|---|
| 2058 | + if (!drm_edid_are_equal(edid, old_edid)) { |
|---|
| 2059 | + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Edid was changed.\n", |
|---|
| 2060 | + connector->base.id, connector->name); |
|---|
| 2061 | + |
|---|
| 2062 | + connector->epoch_counter += 1; |
|---|
| 2063 | + DRM_DEBUG_KMS("Updating change counter to %llu\n", |
|---|
| 2064 | + connector->epoch_counter); |
|---|
| 2065 | + } |
|---|
| 2066 | + } |
|---|
| 2067 | + } |
|---|
| 2068 | + |
|---|
| 1671 | 2069 | drm_object_property_set_value(&connector->base, |
|---|
| 1672 | 2070 | dev->mode_config.non_desktop_property, |
|---|
| 1673 | 2071 | connector->display_info.non_desktop); |
|---|
| .. | .. |
|---|
| 1678 | 2076 | edid, |
|---|
| 1679 | 2077 | &connector->base, |
|---|
| 1680 | 2078 | dev->mode_config.edid_property); |
|---|
| 1681 | | - return ret; |
|---|
| 2079 | + if (ret) |
|---|
| 2080 | + return ret; |
|---|
| 2081 | + return drm_connector_set_tile_property(connector); |
|---|
| 1682 | 2082 | } |
|---|
| 1683 | 2083 | EXPORT_SYMBOL(drm_connector_update_edid_property); |
|---|
| 1684 | 2084 | |
|---|
| .. | .. |
|---|
| 1713 | 2113 | EXPORT_SYMBOL(drm_connector_set_link_status_property); |
|---|
| 1714 | 2114 | |
|---|
| 1715 | 2115 | /** |
|---|
| 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 |
|---|
| 2116 | + * drm_connector_attach_max_bpc_property - attach "max bpc" property |
|---|
| 2117 | + * @connector: connector to attach max bpc property on. |
|---|
| 2118 | + * @min: The minimum bit depth supported by the connector. |
|---|
| 2119 | + * @max: The maximum bit depth supported by the connector. |
|---|
| 1721 | 2120 | * |
|---|
| 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. |
|---|
| 2121 | + * This is used to add support for limiting the bit depth on a connector. |
|---|
| 1729 | 2122 | * |
|---|
| 1730 | 2123 | * Returns: |
|---|
| 1731 | 2124 | * Zero on success, negative errno on failure. |
|---|
| 1732 | 2125 | */ |
|---|
| 1733 | | -int drm_connector_init_panel_orientation_property( |
|---|
| 1734 | | - struct drm_connector *connector, int width, int height) |
|---|
| 2126 | +int drm_connector_attach_max_bpc_property(struct drm_connector *connector, |
|---|
| 2127 | + int min, int max) |
|---|
| 2128 | +{ |
|---|
| 2129 | + struct drm_device *dev = connector->dev; |
|---|
| 2130 | + struct drm_property *prop; |
|---|
| 2131 | + |
|---|
| 2132 | + prop = connector->max_bpc_property; |
|---|
| 2133 | + if (!prop) { |
|---|
| 2134 | + prop = drm_property_create_range(dev, 0, "max bpc", min, max); |
|---|
| 2135 | + if (!prop) |
|---|
| 2136 | + return -ENOMEM; |
|---|
| 2137 | + |
|---|
| 2138 | + connector->max_bpc_property = prop; |
|---|
| 2139 | + } |
|---|
| 2140 | + |
|---|
| 2141 | + drm_object_attach_property(&connector->base, prop, max); |
|---|
| 2142 | + connector->state->max_requested_bpc = max; |
|---|
| 2143 | + connector->state->max_bpc = max; |
|---|
| 2144 | + |
|---|
| 2145 | + return 0; |
|---|
| 2146 | +} |
|---|
| 2147 | +EXPORT_SYMBOL(drm_connector_attach_max_bpc_property); |
|---|
| 2148 | + |
|---|
| 2149 | +/** |
|---|
| 2150 | + * drm_connector_set_vrr_capable_property - sets the variable refresh rate |
|---|
| 2151 | + * capable property for a connector |
|---|
| 2152 | + * @connector: drm connector |
|---|
| 2153 | + * @capable: True if the connector is variable refresh rate capable |
|---|
| 2154 | + * |
|---|
| 2155 | + * Should be used by atomic drivers to update the indicated support for |
|---|
| 2156 | + * variable refresh rate over a connector. |
|---|
| 2157 | + */ |
|---|
| 2158 | +void drm_connector_set_vrr_capable_property( |
|---|
| 2159 | + struct drm_connector *connector, bool capable) |
|---|
| 2160 | +{ |
|---|
| 2161 | + if (!connector->vrr_capable_property) |
|---|
| 2162 | + return; |
|---|
| 2163 | + |
|---|
| 2164 | + drm_object_property_set_value(&connector->base, |
|---|
| 2165 | + connector->vrr_capable_property, |
|---|
| 2166 | + capable); |
|---|
| 2167 | +} |
|---|
| 2168 | +EXPORT_SYMBOL(drm_connector_set_vrr_capable_property); |
|---|
| 2169 | + |
|---|
| 2170 | +/** |
|---|
| 2171 | + * drm_connector_set_panel_orientation - sets the connector's panel_orientation |
|---|
| 2172 | + * @connector: connector for which to set the panel-orientation property. |
|---|
| 2173 | + * @panel_orientation: drm_panel_orientation value to set |
|---|
| 2174 | + * |
|---|
| 2175 | + * This function sets the connector's panel_orientation and attaches |
|---|
| 2176 | + * a "panel orientation" property to the connector. |
|---|
| 2177 | + * |
|---|
| 2178 | + * Calling this function on a connector where the panel_orientation has |
|---|
| 2179 | + * already been set is a no-op (e.g. the orientation has been overridden with |
|---|
| 2180 | + * a kernel commandline option). |
|---|
| 2181 | + * |
|---|
| 2182 | + * It is allowed to call this function with a panel_orientation of |
|---|
| 2183 | + * DRM_MODE_PANEL_ORIENTATION_UNKNOWN, in which case it is a no-op. |
|---|
| 2184 | + * |
|---|
| 2185 | + * Returns: |
|---|
| 2186 | + * Zero on success, negative errno on failure. |
|---|
| 2187 | + */ |
|---|
| 2188 | +int drm_connector_set_panel_orientation( |
|---|
| 2189 | + struct drm_connector *connector, |
|---|
| 2190 | + enum drm_panel_orientation panel_orientation) |
|---|
| 1735 | 2191 | { |
|---|
| 1736 | 2192 | struct drm_device *dev = connector->dev; |
|---|
| 1737 | 2193 | struct drm_display_info *info = &connector->display_info; |
|---|
| 1738 | 2194 | struct drm_property *prop; |
|---|
| 1739 | | - int orientation_quirk; |
|---|
| 1740 | 2195 | |
|---|
| 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) |
|---|
| 2196 | + /* Already set? */ |
|---|
| 2197 | + if (info->panel_orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN) |
|---|
| 1746 | 2198 | return 0; |
|---|
| 2199 | + |
|---|
| 2200 | + /* Don't attach the property if the orientation is unknown */ |
|---|
| 2201 | + if (panel_orientation == DRM_MODE_PANEL_ORIENTATION_UNKNOWN) |
|---|
| 2202 | + return 0; |
|---|
| 2203 | + |
|---|
| 2204 | + info->panel_orientation = panel_orientation; |
|---|
| 1747 | 2205 | |
|---|
| 1748 | 2206 | prop = dev->mode_config.panel_orientation_property; |
|---|
| 1749 | 2207 | if (!prop) { |
|---|
| .. | .. |
|---|
| 1761 | 2219 | info->panel_orientation); |
|---|
| 1762 | 2220 | return 0; |
|---|
| 1763 | 2221 | } |
|---|
| 1764 | | -EXPORT_SYMBOL(drm_connector_init_panel_orientation_property); |
|---|
| 2222 | +EXPORT_SYMBOL(drm_connector_set_panel_orientation); |
|---|
| 2223 | + |
|---|
| 2224 | +/** |
|---|
| 2225 | + * drm_connector_set_panel_orientation_with_quirk - |
|---|
| 2226 | + * set the connector's panel_orientation after checking for quirks |
|---|
| 2227 | + * @connector: connector for which to init the panel-orientation property. |
|---|
| 2228 | + * @panel_orientation: drm_panel_orientation value to set |
|---|
| 2229 | + * @width: width in pixels of the panel, used for panel quirk detection |
|---|
| 2230 | + * @height: height in pixels of the panel, used for panel quirk detection |
|---|
| 2231 | + * |
|---|
| 2232 | + * Like drm_connector_set_panel_orientation(), but with a check for platform |
|---|
| 2233 | + * specific (e.g. DMI based) quirks overriding the passed in panel_orientation. |
|---|
| 2234 | + * |
|---|
| 2235 | + * Returns: |
|---|
| 2236 | + * Zero on success, negative errno on failure. |
|---|
| 2237 | + */ |
|---|
| 2238 | +int drm_connector_set_panel_orientation_with_quirk( |
|---|
| 2239 | + struct drm_connector *connector, |
|---|
| 2240 | + enum drm_panel_orientation panel_orientation, |
|---|
| 2241 | + int width, int height) |
|---|
| 2242 | +{ |
|---|
| 2243 | + int orientation_quirk; |
|---|
| 2244 | + |
|---|
| 2245 | + orientation_quirk = drm_get_panel_orientation_quirk(width, height); |
|---|
| 2246 | + if (orientation_quirk != DRM_MODE_PANEL_ORIENTATION_UNKNOWN) |
|---|
| 2247 | + panel_orientation = orientation_quirk; |
|---|
| 2248 | + |
|---|
| 2249 | + return drm_connector_set_panel_orientation(connector, |
|---|
| 2250 | + panel_orientation); |
|---|
| 2251 | +} |
|---|
| 2252 | +EXPORT_SYMBOL(drm_connector_set_panel_orientation_with_quirk); |
|---|
| 1765 | 2253 | |
|---|
| 1766 | 2254 | int drm_connector_set_obj_prop(struct drm_mode_object *obj, |
|---|
| 1767 | 2255 | struct drm_property *property, |
|---|
| .. | .. |
|---|
| 1807 | 2295 | |
|---|
| 1808 | 2296 | static bool |
|---|
| 1809 | 2297 | drm_mode_expose_to_userspace(const struct drm_display_mode *mode, |
|---|
| 1810 | | - const struct list_head *export_list, |
|---|
| 2298 | + const struct list_head *modes, |
|---|
| 1811 | 2299 | const struct drm_file *file_priv) |
|---|
| 1812 | 2300 | { |
|---|
| 1813 | 2301 | /* |
|---|
| .. | .. |
|---|
| 1823 | 2311 | * while preparing the list of user-modes. |
|---|
| 1824 | 2312 | */ |
|---|
| 1825 | 2313 | if (!file_priv->aspect_ratio_allowed) { |
|---|
| 1826 | | - struct drm_display_mode *mode_itr; |
|---|
| 2314 | + const struct drm_display_mode *mode_itr; |
|---|
| 1827 | 2315 | |
|---|
| 1828 | | - list_for_each_entry(mode_itr, export_list, export_head) |
|---|
| 1829 | | - if (drm_mode_match(mode_itr, mode, |
|---|
| 2316 | + list_for_each_entry(mode_itr, modes, head) { |
|---|
| 2317 | + if (mode_itr->expose_to_userspace && |
|---|
| 2318 | + drm_mode_match(mode_itr, mode, |
|---|
| 1830 | 2319 | DRM_MODE_MATCH_TIMINGS | |
|---|
| 1831 | 2320 | DRM_MODE_MATCH_CLOCK | |
|---|
| 1832 | 2321 | DRM_MODE_MATCH_FLAGS | |
|---|
| 1833 | 2322 | DRM_MODE_MATCH_3D_FLAGS)) |
|---|
| 1834 | 2323 | return false; |
|---|
| 2324 | + } |
|---|
| 1835 | 2325 | } |
|---|
| 1836 | 2326 | |
|---|
| 1837 | 2327 | return true; |
|---|
| .. | .. |
|---|
| 1848 | 2338 | int encoders_count = 0; |
|---|
| 1849 | 2339 | int ret = 0; |
|---|
| 1850 | 2340 | int copied = 0; |
|---|
| 1851 | | - int i; |
|---|
| 1852 | 2341 | struct drm_mode_modeinfo u_mode; |
|---|
| 1853 | 2342 | struct drm_mode_modeinfo __user *mode_ptr; |
|---|
| 1854 | 2343 | uint32_t __user *encoder_ptr; |
|---|
| 1855 | | - LIST_HEAD(export_list); |
|---|
| 1856 | 2344 | |
|---|
| 1857 | 2345 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
|---|
| 1858 | | - return -EINVAL; |
|---|
| 2346 | + return -EOPNOTSUPP; |
|---|
| 1859 | 2347 | |
|---|
| 1860 | 2348 | memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); |
|---|
| 1861 | 2349 | |
|---|
| .. | .. |
|---|
| 1863 | 2351 | if (!connector) |
|---|
| 1864 | 2352 | return -ENOENT; |
|---|
| 1865 | 2353 | |
|---|
| 1866 | | - drm_connector_for_each_possible_encoder(connector, encoder, i) |
|---|
| 1867 | | - encoders_count++; |
|---|
| 2354 | + encoders_count = hweight32(connector->possible_encoders); |
|---|
| 1868 | 2355 | |
|---|
| 1869 | 2356 | if ((out_resp->count_encoders >= encoders_count) && encoders_count) { |
|---|
| 1870 | 2357 | copied = 0; |
|---|
| 1871 | 2358 | encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); |
|---|
| 1872 | 2359 | |
|---|
| 1873 | | - drm_connector_for_each_possible_encoder(connector, encoder, i) { |
|---|
| 2360 | + drm_connector_for_each_possible_encoder(connector, encoder) { |
|---|
| 1874 | 2361 | if (put_user(encoder->base.id, encoder_ptr + copied)) { |
|---|
| 1875 | 2362 | ret = -EFAULT; |
|---|
| 1876 | 2363 | goto out; |
|---|
| .. | .. |
|---|
| 1897 | 2384 | out_resp->connection = connector->status; |
|---|
| 1898 | 2385 | |
|---|
| 1899 | 2386 | /* 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, |
|---|
| 2387 | + list_for_each_entry(mode, &connector->modes, head) { |
|---|
| 2388 | + WARN_ON(mode->expose_to_userspace); |
|---|
| 2389 | + |
|---|
| 2390 | + if (drm_mode_expose_to_userspace(mode, &connector->modes, |
|---|
| 1902 | 2391 | file_priv)) { |
|---|
| 1903 | | - list_add_tail(&mode->export_head, &export_list); |
|---|
| 2392 | + mode->expose_to_userspace = true; |
|---|
| 1904 | 2393 | mode_count++; |
|---|
| 1905 | 2394 | } |
|---|
| 2395 | + } |
|---|
| 1906 | 2396 | |
|---|
| 1907 | 2397 | /* |
|---|
| 1908 | 2398 | * This ioctl is called twice, once to determine how much space is |
|---|
| 1909 | 2399 | * 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 | 2400 | */ |
|---|
| 1915 | 2401 | if ((out_resp->count_modes >= mode_count) && mode_count) { |
|---|
| 1916 | 2402 | copied = 0; |
|---|
| 1917 | 2403 | mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; |
|---|
| 1918 | | - list_for_each_entry(mode, &export_list, export_head) { |
|---|
| 2404 | + list_for_each_entry(mode, &connector->modes, head) { |
|---|
| 2405 | + if (!mode->expose_to_userspace) |
|---|
| 2406 | + continue; |
|---|
| 2407 | + |
|---|
| 2408 | + /* Clear the tag for the next time around */ |
|---|
| 2409 | + mode->expose_to_userspace = false; |
|---|
| 2410 | + |
|---|
| 1919 | 2411 | drm_mode_convert_to_umode(&u_mode, mode); |
|---|
| 1920 | 2412 | /* |
|---|
| 1921 | 2413 | * Reset aspect ratio flags of user-mode, if modes with |
|---|
| .. | .. |
|---|
| 1926 | 2418 | if (copy_to_user(mode_ptr + copied, |
|---|
| 1927 | 2419 | &u_mode, sizeof(u_mode))) { |
|---|
| 1928 | 2420 | ret = -EFAULT; |
|---|
| 2421 | + |
|---|
| 2422 | + /* |
|---|
| 2423 | + * Clear the tag for the rest of |
|---|
| 2424 | + * the modes for the next time around. |
|---|
| 2425 | + */ |
|---|
| 2426 | + list_for_each_entry_continue(mode, &connector->modes, head) |
|---|
| 2427 | + mode->expose_to_userspace = false; |
|---|
| 2428 | + |
|---|
| 1929 | 2429 | mutex_unlock(&dev->mode_config.mutex); |
|---|
| 1930 | 2430 | |
|---|
| 1931 | 2431 | goto out; |
|---|
| 1932 | 2432 | } |
|---|
| 1933 | 2433 | copied++; |
|---|
| 1934 | 2434 | } |
|---|
| 2435 | + } else { |
|---|
| 2436 | + /* Clear the tag for the next time around */ |
|---|
| 2437 | + list_for_each_entry(mode, &connector->modes, head) |
|---|
| 2438 | + mode->expose_to_userspace = false; |
|---|
| 1935 | 2439 | } |
|---|
| 2440 | + |
|---|
| 1936 | 2441 | out_resp->count_modes = mode_count; |
|---|
| 1937 | 2442 | mutex_unlock(&dev->mode_config.mutex); |
|---|
| 1938 | 2443 | |
|---|
| .. | .. |
|---|
| 1974 | 2479 | { |
|---|
| 1975 | 2480 | struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount); |
|---|
| 1976 | 2481 | struct drm_device *dev = tg->dev; |
|---|
| 2482 | + |
|---|
| 1977 | 2483 | mutex_lock(&dev->mode_config.idr_mutex); |
|---|
| 1978 | 2484 | idr_remove(&dev->mode_config.tile_idr, tg->id); |
|---|
| 1979 | 2485 | mutex_unlock(&dev->mode_config.idr_mutex); |
|---|
| .. | .. |
|---|
| 2005 | 2511 | * tile group or NULL if not found. |
|---|
| 2006 | 2512 | */ |
|---|
| 2007 | 2513 | struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, |
|---|
| 2008 | | - char topology[8]) |
|---|
| 2514 | + const char topology[8]) |
|---|
| 2009 | 2515 | { |
|---|
| 2010 | 2516 | struct drm_tile_group *tg; |
|---|
| 2011 | 2517 | int id; |
|---|
| 2518 | + |
|---|
| 2012 | 2519 | mutex_lock(&dev->mode_config.idr_mutex); |
|---|
| 2013 | 2520 | idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) { |
|---|
| 2014 | 2521 | if (!memcmp(tg->group_data, topology, 8)) { |
|---|
| .. | .. |
|---|
| 2032 | 2539 | * identifier for the tile group. |
|---|
| 2033 | 2540 | * |
|---|
| 2034 | 2541 | * RETURNS: |
|---|
| 2035 | | - * new tile group or error. |
|---|
| 2542 | + * new tile group or NULL. |
|---|
| 2036 | 2543 | */ |
|---|
| 2037 | 2544 | struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, |
|---|
| 2038 | | - char topology[8]) |
|---|
| 2545 | + const char topology[8]) |
|---|
| 2039 | 2546 | { |
|---|
| 2040 | 2547 | struct drm_tile_group *tg; |
|---|
| 2041 | 2548 | int ret; |
|---|
| 2042 | 2549 | |
|---|
| 2043 | 2550 | tg = kzalloc(sizeof(*tg), GFP_KERNEL); |
|---|
| 2044 | 2551 | if (!tg) |
|---|
| 2045 | | - return ERR_PTR(-ENOMEM); |
|---|
| 2552 | + return NULL; |
|---|
| 2046 | 2553 | |
|---|
| 2047 | 2554 | kref_init(&tg->refcount); |
|---|
| 2048 | 2555 | memcpy(tg->group_data, topology, 8); |
|---|
| .. | .. |
|---|
| 2054 | 2561 | tg->id = ret; |
|---|
| 2055 | 2562 | } else { |
|---|
| 2056 | 2563 | kfree(tg); |
|---|
| 2057 | | - tg = ERR_PTR(ret); |
|---|
| 2564 | + tg = NULL; |
|---|
| 2058 | 2565 | } |
|---|
| 2059 | 2566 | |
|---|
| 2060 | 2567 | mutex_unlock(&dev->mode_config.idr_mutex); |
|---|