diff options
author | Jani Nikula <jani.nikula@intel.com> | 2022-04-11 16:00:30 +0200 |
---|---|---|
committer | Jani Nikula <jani.nikula@intel.com> | 2022-04-14 15:51:41 +0200 |
commit | 2deaf1c2561d5ec152ee2f2ce547a15b85d38b55 (patch) | |
tree | e2ea8b118d5ae025eee212283e1061f8cc7f4fdc /drivers/gpu/drm/drm_edid.c | |
parent | drm/edid: add typedef for block read function (diff) | |
download | linux-2deaf1c2561d5ec152ee2f2ce547a15b85d38b55.tar.xz linux-2deaf1c2561d5ec152ee2f2ce547a15b85d38b55.zip |
drm/edid: abstract an EDID block read helper
We have an abstraction for the EDID base block read, yet duplicating the
retries and error handling for extension block reads. Introduce a more
generic EDID block read helper.
Switch to the helper piecemeal, starting with drm_edid_get_panel_id(),
which doesn't need or have access to the connector anyway.
The subtle change is switching from drm_edid_block_valid() to
edid_block_check(). We also status print once, not for every attempt.
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/47560f7530e4a7b32b56cb9038178244fe30a4af.1649685475.git.jani.nikula@intel.com
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 58 |
1 files changed, 51 insertions, 7 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 1394750afc9d..11276d226b37 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1670,6 +1670,7 @@ EXPORT_SYMBOL(drm_edid_are_equal); enum edid_block_status { EDID_BLOCK_OK = 0, + EDID_BLOCK_READ_FAIL, EDID_BLOCK_NULL, EDID_BLOCK_ZERO, EDID_BLOCK_HEADER_CORRUPT, @@ -1736,6 +1737,9 @@ static void edid_block_status_print(enum edid_block_status status, switch (status) { case EDID_BLOCK_OK: break; + case EDID_BLOCK_READ_FAIL: + pr_debug("EDID block %d read failed\n", block_num); + break; case EDID_BLOCK_NULL: pr_debug("EDID block %d pointer is NULL\n", block_num); break; @@ -2039,6 +2043,39 @@ EXPORT_SYMBOL(drm_add_override_edid_modes); typedef int read_block_fn(void *context, u8 *buf, unsigned int block, size_t len); +static enum edid_block_status edid_block_read(void *block, unsigned int block_num, + read_block_fn read_block, + void *context) +{ + enum edid_block_status status; + bool is_base_block = block_num == 0; + int try; + + for (try = 0; try < 4; try++) { + if (read_block(context, block, block_num, EDID_LENGTH)) + return EDID_BLOCK_READ_FAIL; + + status = edid_block_check(block, is_base_block); + if (status == EDID_BLOCK_HEADER_REPAIR) { + edid_header_fix(block); + + /* Retry with fixed header, update status if that worked. */ + status = edid_block_check(block, is_base_block); + if (status == EDID_BLOCK_OK) + status = EDID_BLOCK_HEADER_FIXED; + } + + if (edid_block_status_valid(status, edid_block_tag(block))) + break; + + /* Fail early for unrepairable base block all zeros. */ + if (try == 0 && is_base_block && status == EDID_BLOCK_ZERO) + break; + } + + return status; +} + static struct edid *drm_do_get_edid_base_block(struct drm_connector *connector, read_block_fn read_block, void *context) @@ -2237,20 +2274,27 @@ static u32 edid_extract_panel_id(const struct edid *edid) u32 drm_edid_get_panel_id(struct i2c_adapter *adapter) { - const struct edid *edid; - u32 panel_id; - - edid = drm_do_get_edid_base_block(NULL, drm_do_probe_ddc_edid, adapter); + enum edid_block_status status; + void *base_block; + u32 panel_id = 0; /* * There are no manufacturer IDs of 0, so if there is a problem reading * the EDID then we'll just return 0. */ - if (!edid) + + base_block = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (!base_block) return 0; - panel_id = edid_extract_panel_id(edid); - kfree(edid); + status = edid_block_read(base_block, 0, drm_do_probe_ddc_edid, adapter); + + edid_block_status_print(status, base_block, 0); + + if (edid_block_status_valid(status, edid_block_tag(base_block))) + panel_id = edid_extract_panel_id(base_block); + + kfree(base_block); return panel_id; } |