Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ba309f5e authored by Jani Nikula's avatar Jani Nikula Committed by Gerrit - the friendly Code Review server
Browse files

drm: handle override and firmware EDID at drm_do_get_edid() level



Handle debugfs override edid and firmware edid at the low level to
transparently and completely replace the real edid. Previously, we
practically only used the modes from the override EDID, and none of the
other data, such as audio parameters.

This change also prevents actual EDID reads when the EDID is to be
overridden, but retains the DDC probe. This is useful if the reason for
preferring override EDID are problems with reading the data, or
corruption of the data.

Move firmware EDID loading from helper to core, as the functionality
moves to lower level as well. This will result in a change of module
parameter from drm_kms_helper.edid_firmware to drm.edid_firmware, which
arguably makes more sense anyway.

Some future work remains related to override and firmware EDID
validation. Like before, no validation is done for override EDID. The
firmware EDID is validated separately in the loader. Some unification
and deduplication would be in order, to validate all of them at the
drm_do_get_edid() level, like "real" EDIDs.

v2: move firmware loading to core

v3: rebase, commit message refresh

Cc: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Tested-by: default avatarAbdiel Janulgue <abdiel.janulgue@linux.intel.com>
Reviewed-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Acked-by: default avatarDave Airlie <airlied@gmail.com>
Signed-off-by: default avatarJani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/1e8a710bcac46e5136c1a7b430074893c81f364a.1505203831.git.jani.nikula@intel.com
Git-commit: 53fd40a90f3c0bdad86ec266ee5df833f54ace39
Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git


Change-Id: I5003038a40d3eeb469dc49257650f4194f084231
[tanmay@codeaurora.org: resolved trivial merge conflicts]
Signed-off-by: default avatarTanmay Shah <tanmay@codeaurora.org>
parent d6bf038c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -948,7 +948,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
			The filter can be disabled or changed to another
			driver later using sysfs.

	drm_kms_helper.edid_firmware=[<connector>:]<file>[,[<connector>:]<file>]
	drm.edid_firmware=[<connector>:]<file>[,[<connector>:]<file>]
			Broken monitors, graphic adapters, KVMs and EDIDless
			panels may send no or incorrect EDID data sets.
			This parameter allows to specify an EDID data sets
+1 −1
Original line number Diff line number Diff line
@@ -63,7 +63,7 @@ config DRM_FBDEV_EMULATION

config DRM_LOAD_EDID_FIRMWARE
	bool "Allow to specify an EDID data set instead of probing for it"
	depends on DRM_KMS_HELPER
	depends on DRM
	help
	  Say Y here, if you want to use EDID data to be loaded from the
	  /lib/firmware directory or one of the provided built-in
+1 −1
Original line number Diff line number Diff line
@@ -20,12 +20,12 @@ drm-$(CONFIG_PCI) += ati_pcigart.o
drm-$(CONFIG_DRM_PANEL) += drm_panel.o
drm-$(CONFIG_OF) += drm_of.o
drm-$(CONFIG_AGP) += drm_agpsupport.o
drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o

drm-y += $(drm-m)

drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \
		drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o
drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o

+15 −0
Original line number Diff line number Diff line
@@ -1501,6 +1501,10 @@ drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int block, size_t len)
 * level, drivers must make all reasonable efforts to expose it as an I2C
 * adapter and use drm_get_edid() instead of abusing this function.
 *
 * The EDID may be overridden using debugfs override_edid or firmare EDID
 * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority
 * order. Having either of them bypasses actual EDID reads.
 *
 * Return: Pointer to valid EDID or NULL if we couldn't find any.
 */
struct edid *drm_do_get_edid(struct drm_connector *connector,
@@ -1511,6 +1515,17 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
	int i, j = 0, valid_extensions = 0;
	u8 *block, *new;
	bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS);
	struct edid *override = NULL;

	if (connector->override_edid)
		override = drm_edid_duplicate((const struct edid *)
					      connector->edid_blob_ptr->data);

	if (!override)
		override = drm_load_edid_firmware(connector);

	if (!IS_ERR_OR_NULL(override))
		return override;

	if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
		return NULL;
+1 −16
Original line number Diff line number Diff line
@@ -199,22 +199,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
		goto prune;
	}

	if (connector->override_edid) {
		struct edid *edid = (struct edid *) connector->edid_blob_ptr->data;

		count = drm_add_edid_modes(connector, edid);
		drm_edid_to_eld(connector, edid);
	} else {
		struct edid *edid = drm_load_edid_firmware(connector);
		if (!IS_ERR_OR_NULL(edid)) {
			drm_mode_connector_update_edid_property(connector, edid);
			count = drm_add_edid_modes(connector, edid);
			drm_edid_to_eld(connector, edid);
			kfree(edid);
		}
		if (count == 0)
	count = (*connector_funcs->get_modes)(connector);
	}

	if (count == 0 && connector->status == connector_status_connected)
		count = drm_add_modes_noedid(connector, 1024, 768);