Add a replacement for drm_get_edid that handles override and firmware EDID at the low level, and handles EDID property update, ELD update, and adds modes. This allows for a more transparent EDID override, and makes it possible to unify the drivers better. It also allows reusing the EDID cached in the property, and only probing the DDC. Signed-off-by: Jani Nikula <jani.nikula@xxxxxxxxx> --- drivers/gpu/drm/drm_connector.c | 60 ++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_probe_helper.c | 7 +++++ include/drm/drm_connector.h | 6 ++++ 3 files changed, 73 insertions(+) diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 3115db2ae6b1..b9636c98dbf3 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -1086,6 +1086,66 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, } EXPORT_SYMBOL(drm_mode_connector_update_edid_property); +/** + * drm_mode_connector_get_edid - do it all replacement for drm_get_edid() + * @connector: connector to probe + * @adapter: I2C adapter to use for DDC + * @edid_out: if non-NULL, get EDID here, must be kfree'd by caller + * @no_cache: false to allow using cached EDID, true to force read + * + * drm_get_edid() on steroids. Handle debugfs override edid, firmware edid, and + * caching at the low level. Add modes, update ELD and EDID property. Using this + * prevents override/firmware edid usage at the higher level. + * + * @return: Number of modes from drm_add_edid_modes(). + */ +int drm_mode_connector_get_edid(struct drm_connector *connector, + struct i2c_adapter *adapter, + struct edid **edid_out, + bool no_cache) +{ + struct drm_property_blob *prop = connector->edid_blob_ptr; + struct edid *edid = NULL; + int count = 0; + + /* + * If a driver uses this function on a connector, override/firmware edid + * will only be used at this level. + */ + connector->low_level_override = true; + + if ((connector->override_edid || !no_cache) && prop && prop->data) + edid = drm_edid_duplicate((struct edid *) prop->data); + + if (!edid) { + edid = drm_load_edid_firmware(connector); + if (IS_ERR(edid)) + edid = NULL; + } + + if (edid) { + /* Require successful probe for override/cached/firmware EDID */ + if (drm_probe_ddc(adapter)) + drm_get_displayid(connector, edid); + else + edid = NULL; + } else { + edid = drm_get_edid(connector, adapter); + } + + count = drm_add_edid_modes(connector, edid); + drm_edid_to_eld(connector, edid); + drm_mode_connector_update_edid_property(connector, edid); + + if (edid_out) + *edid_out = edid; + else + kfree(edid); + + return count; +} +EXPORT_SYMBOL(drm_mode_connector_get_edid); + int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, struct drm_property *property, uint64_t value) diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 431349673846..20a175a775d6 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -167,6 +167,13 @@ static bool bypass_edid(struct drm_connector *connector, int *count) { struct edid *edid; + /* + * If a driver uses drm_connector_get_edid() on a connector, + * override/firmware edid will only be used at that level. + */ + if (connector->low_level_override) + return false; + if (connector->override_edid) { edid = (struct edid *) connector->edid_blob_ptr->data; diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 6e352a0b5c81..0c85ddc422de 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -25,6 +25,7 @@ #include <linux/list.h> #include <linux/ctype.h> +#include <linux/i2c.h> #include <drm/drm_mode_object.h> #include <uapi/drm/drm_mode.h> @@ -727,6 +728,7 @@ struct drm_connector { /* forced on connector */ struct drm_cmdline_mode cmdline_mode; enum drm_connector_force force; + bool low_level_override; bool override_edid; #define DRM_CONNECTOR_MAX_ENCODER 3 @@ -837,6 +839,10 @@ int drm_mode_connector_set_path_property(struct drm_connector *connector, int drm_mode_connector_set_tile_property(struct drm_connector *connector); int drm_mode_connector_update_edid_property(struct drm_connector *connector, const struct edid *edid); +int drm_mode_connector_get_edid(struct drm_connector *connector, + struct i2c_adapter *adapter, + struct edid **edid_out, + bool no_cache); /** * struct drm_tile_group - Tile group metadata -- 2.1.4 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel