diff options
Diffstat (limited to 'drivers/gpu/drm/drm_connector.c')
| -rw-r--r-- | drivers/gpu/drm/drm_connector.c | 401 |
1 files changed, 320 insertions, 81 deletions
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index dd40eff0911c..2166000ed057 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -92,6 +92,7 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { { DRM_MODE_CONNECTOR_DSI, "DSI" }, { DRM_MODE_CONNECTOR_DPI, "DPI" }, { DRM_MODE_CONNECTOR_WRITEBACK, "Writeback" }, + { DRM_MODE_CONNECTOR_SPI, "SPI" }, }; void drm_connector_ida_init(void) @@ -139,8 +140,8 @@ static void drm_connector_get_cmdline_mode(struct drm_connector *connector) connector->force = mode->force; } - DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", - connector->name, + DRM_DEBUG_KMS("cmdline mode for connector %s %s %dx%d@%dHz%s%s%s\n", + connector->name, mode->name, mode->xres, mode->yres, mode->refresh_specified ? mode->refresh : 60, mode->rb ? " reduced blanking" : "", @@ -245,6 +246,7 @@ int drm_connector_init(struct drm_device *dev, INIT_LIST_HEAD(&connector->modes); mutex_init(&connector->mutex); connector->edid_blob_ptr = NULL; + connector->tile_blob_ptr = NULL; connector->status = connector_status_unknown; connector->display_info.panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN; @@ -272,6 +274,9 @@ int drm_connector_init(struct drm_device *dev, drm_object_attach_property(&connector->base, config->non_desktop_property, 0); + drm_object_attach_property(&connector->base, + config->tile_property, + 0); if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { drm_object_attach_property(&connector->base, config->prop_crtc_id, 0); @@ -293,6 +298,41 @@ out_put: EXPORT_SYMBOL(drm_connector_init); /** + * drm_connector_init_with_ddc - Init a preallocated connector + * @dev: DRM device + * @connector: the connector to init + * @funcs: callbacks for this connector + * @connector_type: user visible type of the connector + * @ddc: pointer to the associated ddc adapter + * + * Initialises a preallocated connector. Connectors should be + * subclassed as part of driver connector objects. + * + * Ensures that the ddc field of the connector is correctly set. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_connector_init_with_ddc(struct drm_device *dev, + struct drm_connector *connector, + const struct drm_connector_funcs *funcs, + int connector_type, + struct i2c_adapter *ddc) +{ + int ret; + + ret = drm_connector_init(dev, connector, funcs, connector_type); + if (ret) + return ret; + + /* provide ddc symlink in sysfs */ + connector->ddc = ddc; + + return ret; +} +EXPORT_SYMBOL(drm_connector_init_with_ddc); + +/** * drm_connector_attach_edid_property - attach edid property. * @connector: the connector * @@ -325,8 +365,6 @@ EXPORT_SYMBOL(drm_connector_attach_edid_property); int drm_connector_attach_encoder(struct drm_connector *connector, struct drm_encoder *encoder) { - int i; - /* * In the past, drivers have attempted to model the static association * of connector to encoder in simple connector/encoder devices using a @@ -341,18 +379,15 @@ int drm_connector_attach_encoder(struct drm_connector *connector, if (WARN_ON(connector->encoder)) return -EINVAL; - for (i = 0; i < ARRAY_SIZE(connector->encoder_ids); i++) { - if (connector->encoder_ids[i] == 0) { - connector->encoder_ids[i] = encoder->base.id; - return 0; - } - } - return -ENOMEM; + connector->possible_encoders |= drm_encoder_mask(encoder); + + return 0; } EXPORT_SYMBOL(drm_connector_attach_encoder); /** - * drm_connector_has_possible_encoder - check if the connector and encoder are assosicated with each other + * drm_connector_has_possible_encoder - check if the connector and encoder are + * associated with each other * @connector: the connector * @encoder: the encoder * @@ -362,15 +397,7 @@ EXPORT_SYMBOL(drm_connector_attach_encoder); bool drm_connector_has_possible_encoder(struct drm_connector *connector, struct drm_encoder *encoder) { - struct drm_encoder *enc; - int i; - - drm_connector_for_each_possible_encoder(connector, enc, i) { - if (enc == encoder) - return true; - } - - return false; + return connector->possible_encoders & drm_encoder_mask(encoder); } EXPORT_SYMBOL(drm_connector_has_possible_encoder); @@ -440,7 +467,10 @@ EXPORT_SYMBOL(drm_connector_cleanup); * drm_connector_register - register a connector * @connector: the connector to register * - * Register userspace interfaces for a connector + * Register userspace interfaces for a connector. Only call this for connectors + * which can be hotplugged after drm_dev_register() has been called already, + * e.g. DP MST connectors. All other connectors will be registered automatically + * when calling drm_dev_register(). * * Returns: * Zero on success, error code on failure. @@ -460,10 +490,7 @@ int drm_connector_register(struct drm_connector *connector) if (ret) goto unlock; - ret = drm_debugfs_connector_add(connector); - if (ret) { - goto err_sysfs; - } + drm_debugfs_connector_add(connector); if (connector->funcs->late_register) { ret = connector->funcs->late_register(connector); @@ -478,7 +505,6 @@ int drm_connector_register(struct drm_connector *connector) err_debugfs: drm_debugfs_connector_remove(connector); -err_sysfs: drm_sysfs_connector_remove(connector); unlock: mutex_unlock(&connector->mutex); @@ -490,7 +516,10 @@ EXPORT_SYMBOL(drm_connector_register); * drm_connector_unregister - unregister a connector * @connector: the connector to unregister * - * Unregister userspace interfaces for a connector + * Unregister userspace interfaces for a connector. Only call this for + * connectors which have registered explicitly by calling drm_dev_register(), + * since connectors are unregistered automatically when drm_dev_unregister() is + * called. */ void drm_connector_unregister(struct drm_connector *connector) { @@ -683,7 +712,7 @@ void drm_connector_list_iter_end(struct drm_connector_list_iter *iter) __drm_connector_put_safe(iter->conn); spin_unlock_irqrestore(&config->connector_list_lock, flags); } - lock_release(&connector_list_iter_dep_map, 0, _RET_IP_); + lock_release(&connector_list_iter_dep_map, _RET_IP_); } EXPORT_SYMBOL(drm_connector_list_iter_end); @@ -819,12 +848,64 @@ static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, drm_tv_subconnector_enum_list) -static struct drm_prop_enum_list drm_cp_enum_list[] = { - { DRM_MODE_CONTENT_PROTECTION_UNDESIRED, "Undesired" }, - { DRM_MODE_CONTENT_PROTECTION_DESIRED, "Desired" }, - { DRM_MODE_CONTENT_PROTECTION_ENABLED, "Enabled" }, +static const struct drm_prop_enum_list hdmi_colorspaces[] = { + /* For Default case, driver will set the colorspace */ + { DRM_MODE_COLORIMETRY_DEFAULT, "Default" }, + /* Standard Definition Colorimetry based on CEA 861 */ + { DRM_MODE_COLORIMETRY_SMPTE_170M_YCC, "SMPTE_170M_YCC" }, + { DRM_MODE_COLORIMETRY_BT709_YCC, "BT709_YCC" }, + /* Standard Definition Colorimetry based on IEC 61966-2-4 */ + { DRM_MODE_COLORIMETRY_XVYCC_601, "XVYCC_601" }, + /* High Definition Colorimetry based on IEC 61966-2-4 */ + { DRM_MODE_COLORIMETRY_XVYCC_709, "XVYCC_709" }, + /* Colorimetry based on IEC 61966-2-1/Amendment 1 */ + { DRM_MODE_COLORIMETRY_SYCC_601, "SYCC_601" }, + /* Colorimetry based on IEC 61966-2-5 [33] */ + { DRM_MODE_COLORIMETRY_OPYCC_601, "opYCC_601" }, + /* Colorimetry based on IEC 61966-2-5 */ + { DRM_MODE_COLORIMETRY_OPRGB, "opRGB" }, + /* Colorimetry based on ITU-R BT.2020 */ + { DRM_MODE_COLORIMETRY_BT2020_CYCC, "BT2020_CYCC" }, + /* Colorimetry based on ITU-R BT.2020 */ + { DRM_MODE_COLORIMETRY_BT2020_RGB, "BT2020_RGB" }, + /* Colorimetry based on ITU-R BT.2020 */ + { DRM_MODE_COLORIMETRY_BT2020_YCC, "BT2020_YCC" }, + /* Added as part of Additional Colorimetry Extension in 861.G */ + { DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65, "DCI-P3_RGB_D65" }, + { DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER, "DCI-P3_RGB_Theater" }, +}; + +/* + * As per DP 1.4a spec, 2.2.5.7.5 VSC SDP Payload for Pixel Encoding/Colorimetry + * Format Table 2-120 + */ +static const struct drm_prop_enum_list dp_colorspaces[] = { + /* For Default case, driver will set the colorspace */ + { DRM_MODE_COLORIMETRY_DEFAULT, "Default" }, + { DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED, "RGB_Wide_Gamut_Fixed_Point" }, + /* Colorimetry based on scRGB (IEC 61966-2-2) */ + { DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT, "RGB_Wide_Gamut_Floating_Point" }, + /* Colorimetry based on IEC 61966-2-5 */ + { DRM_MODE_COLORIMETRY_OPRGB, "opRGB" }, + /* Colorimetry based on SMPTE RP 431-2 */ + { DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65, "DCI-P3_RGB_D65" }, + /* Colorimetry based on ITU-R BT.2020 */ + { DRM_MODE_COLORIMETRY_BT2020_RGB, "BT2020_RGB" }, + { DRM_MODE_COLORIMETRY_BT601_YCC, "BT601_YCC" }, + { DRM_MODE_COLORIMETRY_BT709_YCC, "BT709_YCC" }, + /* Standard Definition Colorimetry based on IEC 61966-2-4 */ + { DRM_MODE_COLORIMETRY_XVYCC_601, "XVYCC_601" }, + /* High Definition Colorimetry based on IEC 61966-2-4 */ + { DRM_MODE_COLORIMETRY_XVYCC_709, "XVYCC_709" }, + /* Colorimetry based on IEC 61966-2-1/Amendment 1 */ + { DRM_MODE_COLORIMETRY_SYCC_601, "SYCC_601" }, + /* Colorimetry based on IEC 61966-2-5 [33] */ + { DRM_MODE_COLORIMETRY_OPYCC_601, "opYCC_601" }, + /* Colorimetry based on ITU-R BT.2020 */ + { DRM_MODE_COLORIMETRY_BT2020_CYCC, "BT2020_CYCC" }, + /* Colorimetry based on ITU-R BT.2020 */ + { DRM_MODE_COLORIMETRY_BT2020_YCC, "BT2020_YCC" }, }; -DRM_ENUM_NAME_FN(drm_get_content_protection_name, drm_cp_enum_list) /** * DOC: standard connector properties @@ -927,10 +1008,113 @@ DRM_ENUM_NAME_FN(drm_get_content_protection_name, drm_cp_enum_list) * - If the state is DESIRED, kernel should attempt to re-authenticate the * link whenever possible. This includes across disable/enable, dpms, * hotplug, downstream device changes, link status failures, etc.. - * - Userspace is responsible for polling the property to determine when - * the value transitions from ENABLED to DESIRED. This signifies the link - * is no longer protected and userspace should take appropriate action - * (whatever that might be). + * - Kernel sends uevent with the connector id and property id through + * @drm_hdcp_update_content_protection, upon below kernel triggered + * scenarios: + * + * - DESIRED -> ENABLED (authentication success) + * - ENABLED -> DESIRED (termination of authentication) + * - Please note no uevents for userspace triggered property state changes, + * which can't fail such as + * + * - DESIRED/ENABLED -> UNDESIRED + * - UNDESIRED -> DESIRED + * - Userspace is responsible for polling the property or listen to uevents + * to determine when the value transitions from ENABLED to DESIRED. + * This signifies the link is no longer protected and userspace should + * take appropriate action (whatever that might be). + * + * HDCP Content Type: + * This Enum property is used by the userspace to declare the content type + * of the display stream, to kernel. Here display stream stands for any + * display content that userspace intended to display through HDCP + * encryption. + * + * Content Type of a stream is decided by the owner of the stream, as + * "HDCP Type0" or "HDCP Type1". + * + * The value of the property can be one of the below: + * - "HDCP Type0": DRM_MODE_HDCP_CONTENT_TYPE0 = 0 + * - "HDCP Type1": DRM_MODE_HDCP_CONTENT_TYPE1 = 1 + * + * When kernel starts the HDCP authentication (see "Content Protection" + * for details), it uses the content type in "HDCP Content Type" + * for performing the HDCP authentication with the display sink. + * + * Please note in HDCP spec versions, a link can be authenticated with + * HDCP 2.2 for Content Type 0/Content Type 1. Where as a link can be + * authenticated with HDCP1.4 only for Content Type 0(though it is implicit + * in nature. As there is no reference for Content Type in HDCP1.4). + * + * HDCP2.2 authentication protocol itself takes the "Content Type" as a + * parameter, which is a input for the DP HDCP2.2 encryption algo. + * + * In case of Type 0 content protection request, kernel driver can choose + * either of HDCP spec versions 1.4 and 2.2. When HDCP2.2 is used for + * "HDCP Type 0", a HDCP 2.2 capable repeater in the downstream can send + * that content to a HDCP 1.4 authenticated HDCP sink (Type0 link). + * But if the content is classified as "HDCP Type 1", above mentioned + * HDCP 2.2 repeater wont send the content to the HDCP sink as it can't + * authenticate the HDCP1.4 capable sink for "HDCP Type 1". + * + * Please note userspace can be ignorant of the HDCP versions used by the + * kernel driver to achieve the "HDCP Content Type". + * + * At current scenario, classifying a content as Type 1 ensures that the + * content will be displayed only through the HDCP2.2 encrypted link. + * + * Note that the HDCP Content Type property is introduced at HDCP 2.2, and + * defaults to type 0. It is only exposed by drivers supporting HDCP 2.2 + * (hence supporting Type 0 and Type 1). Based on how next versions of + * HDCP specs are defined content Type could be used for higher versions + * too. + * + * If content type is changed when "Content Protection" is not UNDESIRED, + * then kernel will disable the HDCP and re-enable with new type in the + * same atomic commit. And when "Content Protection" is ENABLED, it means + * that link is HDCP authenticated and encrypted, for the transmission of + * the Type of stream mentioned at "HDCP Content Type". + * + * HDR_OUTPUT_METADATA: + * Connector property to enable userspace to send HDR Metadata to + * driver. This metadata is based on the composition and blending + * policies decided by user, taking into account the hardware and + * sink capabilities. The driver gets this metadata and creates a + * Dynamic Range and Mastering Infoframe (DRM) in case of HDMI, + * SDP packet (Non-audio INFOFRAME SDP v1.3) for DP. This is then + * sent to sink. This notifies the sink of the upcoming frame's Color + * Encoding and Luminance parameters. + * + * Userspace first need to detect the HDR capabilities of sink by + * reading and parsing the EDID. Details of HDR metadata for HDMI + * are added in CTA 861.G spec. For DP , its defined in VESA DP + * Standard v1.4. It needs to then get the metadata information + * of the video/game/app content which are encoded in HDR (basically + * using HDR transfer functions). With this information it needs to + * decide on a blending policy and compose the relevant + * layers/overlays into a common format. Once this blending is done, + * userspace will be aware of the metadata of the composed frame to + * be send to sink. It then uses this property to communicate this + * metadata to driver which then make a Infoframe packet and sends + * to sink based on the type of encoder connected. + * + * Userspace will be responsible to do Tone mapping operation in case: + * - Some layers are HDR and others are SDR + * - HDR layers luminance is not same as sink + * + * It will even need to do colorspace conversion and get all layers + * to one common colorspace for blending. It can use either GL, Media + * or display engine to get this done based on the capabilties of the + * associated hardware. + * + * Driver expects metadata to be put in &struct hdr_output_metadata + * structure from userspace. This is received as blob and stored in + * &drm_connector_state.hdr_output_metadata. It parses EDID and saves the + * sink metadata in &struct hdr_sink_metadata, as + * &drm_connector.hdr_sink_metadata. Driver uses + * drm_hdmi_infoframe_set_hdr_metadata() helper to set the HDR metadata, + * hdmi_drm_infoframe_pack() to pack the infoframe as per spec, in case of + * HDMI encoder. * * max bpc: * This range property is used by userspace to limit the bit depth. When @@ -1027,6 +1211,12 @@ int drm_connector_create_standard_properties(struct drm_device *dev) return -ENOMEM; dev->mode_config.non_desktop_property = prop; + prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, + "HDR_OUTPUT_METADATA", 0); + if (!prop) + return -ENOMEM; + dev->mode_config.hdr_output_metadata_property = prop; + return 0; } @@ -1385,12 +1575,6 @@ EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); * * The driver may place further restrictions within these minimum * and maximum bounds. - * - * The semantics for the vertical blank timestamp differ when - * variable refresh rate is active. The vertical blank timestamp - * is defined to be an estimate using the current mode's fixed - * refresh rate timings. The semantics for the page-flip event - * timestamp remain the same. */ /** @@ -1485,67 +1669,117 @@ int drm_connector_attach_scaling_mode_property(struct drm_connector *connector, EXPORT_SYMBOL(drm_connector_attach_scaling_mode_property); /** - * drm_connector_attach_content_protection_property - attach content protection - * property + * drm_mode_create_aspect_ratio_property - create aspect ratio property + * @dev: DRM device * - * @connector: connector to attach CP property on. + * Called by a driver the first time it's needed, must be attached to desired + * connectors. * - * This is used to add support for content protection on select connectors. - * Content Protection is intentionally vague to allow for different underlying - * technologies, however it is most implemented by HDCP. + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_create_aspect_ratio_property(struct drm_device *dev) +{ + if (dev->mode_config.aspect_ratio_property) + return 0; + + dev->mode_config.aspect_ratio_property = + drm_property_create_enum(dev, 0, "aspect ratio", + drm_aspect_ratio_enum_list, + ARRAY_SIZE(drm_aspect_ratio_enum_list)); + + if (dev->mode_config.aspect_ratio_property == NULL) + return -ENOMEM; + + return 0; +} +EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); + +/** + * DOC: standard connector properties * - * The content protection will be set to &drm_connector_state.content_protection + * Colorspace: + * This property helps select a suitable colorspace based on the sink + * capability. Modern sink devices support wider gamut like BT2020. + * This helps switch to BT2020 mode if the BT2020 encoded video stream + * is being played by the user, same for any other colorspace. Thereby + * giving a good visual experience to users. + * + * The expectation from userspace is that it should parse the EDID + * and get supported colorspaces. Use this property and switch to the + * one supported. Sink supported colorspaces should be retrieved by + * userspace from EDID and driver will not explicitly expose them. + * + * Basically the expectation from userspace is: + * - Set up CRTC DEGAMMA/CTM/GAMMA to convert to some sink + * colorspace + * - Set this new property to let the sink know what it + * converted the CRTC output to. + * - This property is just to inform sink what colorspace + * source is trying to drive. + * + * Because between HDMI and DP have different colorspaces, + * drm_mode_create_hdmi_colorspace_property() is used for HDMI connector and + * drm_mode_create_dp_colorspace_property() is used for DP connector. + */ + +/** + * drm_mode_create_hdmi_colorspace_property - create hdmi colorspace property + * @connector: connector to create the Colorspace property on. + * + * Called by a driver the first time it's needed, must be attached to desired + * HDMI connectors. * * Returns: - * Zero on success, negative errno on failure. + * Zero on success, negative errono on failure. */ -int drm_connector_attach_content_protection_property( - struct drm_connector *connector) +int drm_mode_create_hdmi_colorspace_property(struct drm_connector *connector) { struct drm_device *dev = connector->dev; - struct drm_property *prop; - prop = drm_property_create_enum(dev, 0, "Content Protection", - drm_cp_enum_list, - ARRAY_SIZE(drm_cp_enum_list)); - if (!prop) - return -ENOMEM; + if (connector->colorspace_property) + return 0; - drm_object_attach_property(&connector->base, prop, - DRM_MODE_CONTENT_PROTECTION_UNDESIRED); + connector->colorspace_property = + drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "Colorspace", + hdmi_colorspaces, + ARRAY_SIZE(hdmi_colorspaces)); - connector->content_protection_property = prop; + if (!connector->colorspace_property) + return -ENOMEM; return 0; } -EXPORT_SYMBOL(drm_connector_attach_content_protection_property); +EXPORT_SYMBOL(drm_mode_create_hdmi_colorspace_property); /** - * drm_mode_create_aspect_ratio_property - create aspect ratio property - * @dev: DRM device + * drm_mode_create_dp_colorspace_property - create dp colorspace property + * @connector: connector to create the Colorspace property on. * * Called by a driver the first time it's needed, must be attached to desired - * connectors. + * DP connectors. * * Returns: - * Zero on success, negative errno on failure. + * Zero on success, negative errono on failure. */ -int drm_mode_create_aspect_ratio_property(struct drm_device *dev) +int drm_mode_create_dp_colorspace_property(struct drm_connector *connector) { - if (dev->mode_config.aspect_ratio_property) + struct drm_device *dev = connector->dev; + + if (connector->colorspace_property) return 0; - dev->mode_config.aspect_ratio_property = - drm_property_create_enum(dev, 0, "aspect ratio", - drm_aspect_ratio_enum_list, - ARRAY_SIZE(drm_aspect_ratio_enum_list)); + connector->colorspace_property = + drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "Colorspace", + dp_colorspaces, + ARRAY_SIZE(dp_colorspaces)); - if (dev->mode_config.aspect_ratio_property == NULL) + if (!connector->colorspace_property) return -ENOMEM; return 0; } -EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property); +EXPORT_SYMBOL(drm_mode_create_dp_colorspace_property); /** * drm_mode_create_content_type_property - create content type property @@ -1634,6 +1868,8 @@ EXPORT_SYMBOL(drm_connector_set_path_property); * This looks up the tile information for a connector, and creates a * property for userspace to parse if it exists. The property is of * the form of 8 integers using ':' as a separator. + * This is used for dual port tiled displays with DisplayPort SST + * or DisplayPort MST connectors. * * Returns: * Zero on success, errno on failure. @@ -1677,6 +1913,9 @@ EXPORT_SYMBOL(drm_connector_set_tile_property); * * This function creates a new blob modeset object and assigns its id to the * connector's edid property. + * Since we also parse tile information from EDID's displayID block, we also + * set the connector's tile property here. See drm_connector_set_tile_property() + * for more details. * * Returns: * Zero on success, negative errno on failure. @@ -1718,7 +1957,9 @@ int drm_connector_update_edid_property(struct drm_connector *connector, edid, &connector->base, dev->mode_config.edid_property); - return ret; + if (ret) + return ret; + return drm_connector_set_tile_property(connector); } EXPORT_SYMBOL(drm_connector_update_edid_property); @@ -1940,7 +2181,6 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, int encoders_count = 0; int ret = 0; int copied = 0; - int i; struct drm_mode_modeinfo u_mode; struct drm_mode_modeinfo __user *mode_ptr; uint32_t __user *encoder_ptr; @@ -1955,14 +2195,13 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, if (!connector) return -ENOENT; - drm_connector_for_each_possible_encoder(connector, encoder, i) - encoders_count++; + encoders_count = hweight32(connector->possible_encoders); if ((out_resp->count_encoders >= encoders_count) && encoders_count) { copied = 0; encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); - drm_connector_for_each_possible_encoder(connector, encoder, i) { + drm_connector_for_each_possible_encoder(connector, encoder) { if (put_user(encoder->base.id, encoder_ptr + copied)) { ret = -EFAULT; goto out; |
