summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJani Nikula <jani.nikula@intel.com>2017-09-12 11:19:26 +0300
committerGerrit - the friendly Code Review server <code-review@localhost>2019-07-30 15:32:17 -0700
commitba309f5e08f4744ca641e4dfe0771fb0926c74de (patch)
tree29c0b9f01dce52277aa1817826c791591243fc15
parentd6bf038c87da4cf877dc65324a7483eca7b38059 (diff)
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: Abdiel Janulgue <abdiel.janulgue@linux.intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Acked-by: Dave Airlie <airlied@gmail.com> Signed-off-by: Jani 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: Tanmay Shah <tanmay@codeaurora.org>
-rw-r--r--Documentation/kernel-parameters.txt2
-rw-r--r--drivers/gpu/drm/Kconfig2
-rw-r--r--drivers/gpu/drm/Makefile2
-rw-r--r--drivers/gpu/drm/drm_edid.c15
-rw-r--r--drivers/gpu/drm/drm_probe_helper.c17
5 files changed, 19 insertions, 19 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 69b096e6ac45..f9500fb1498b 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -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
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 021d8391abea..65d6e1db8db8 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -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
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index ea0d5ea57213..d4e3cf4356d7 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -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
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index fbd717324328..d3f3e33230f2 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -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;
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index 7c6fc77c0b7b..81dfc23e1c6a 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -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);
- }
+ count = (*connector_funcs->get_modes)(connector);
if (count == 0 && connector->status == connector_status_connected)
count = drm_add_modes_noedid(connector, 1024, 768);