From 8c5884e8d739ed0271da051034f5c4f475a00b55 Mon Sep 17 00:00:00 2001 From: Arthur Heymans Date: Sun, 30 Apr 2017 08:28:05 +0200 Subject: [PATCH] lib/edid.c: Differentiate between absent and non-conformant EDID Change-Id: Id90aa210ff72092c4ab638a7bafb82bd11889bdc Signed-off-by: Arthur Heymans Reviewed-on: https://review.coreboot.org/19502 Tested-by: build bot (Jenkins) Reviewed-by: Nico Huber --- src/drivers/parade/ps8640/ps8640.c | 2 +- src/include/edid.h | 6 ++++++ src/lib/edid.c | 33 +++++++++++++++--------------- src/soc/nvidia/tegra124/dp.c | 2 +- src/soc/nvidia/tegra210/dp.c | 2 +- src/soc/rockchip/common/edp.c | 2 +- src/soc/rockchip/rk3288/hdmi.c | 2 +- 7 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/drivers/parade/ps8640/ps8640.c b/src/drivers/parade/ps8640/ps8640.c index 95965601ec..62bbf635b8 100644 --- a/src/drivers/parade/ps8640/ps8640.c +++ b/src/drivers/parade/ps8640/ps8640.c @@ -47,7 +47,7 @@ int ps8640_get_edid(uint8_t bus, uint8_t chip, struct edid *out) } } - if (decode_edid(edid, edid_size, out)) { + if (decode_edid(edid, edid_size, out) != EDID_CONFORMANT) { printk(BIOS_INFO, "Failed to decode EDID.\n"); return -1; } diff --git a/src/include/edid.h b/src/include/edid.h index cf812583a5..100dbe9ba3 100644 --- a/src/include/edid.h +++ b/src/include/edid.h @@ -91,6 +91,12 @@ struct edid { int hdmi_monitor_detected; }; +enum edid_status { + EDID_CONFORMANT, + EDID_NOT_CONFORMANT, + EDID_ABSENT, +}; + /* Defined in src/lib/edid.c */ int decode_edid(unsigned char *edid, int size, struct edid *out); void edid_set_framebuffer_bits_per_pixel(struct edid *edid, int fb_bpp, diff --git a/src/lib/edid.c b/src/lib/edid.c index 58dd813dd2..7b7098a0e8 100644 --- a/src/lib/edid.c +++ b/src/lib/edid.c @@ -66,7 +66,7 @@ struct edid_context { int seen_non_detailed_descriptor; int warning_excessive_dotclock_correction; int warning_zero_preferred_refresh; - int conformant; + enum edid_status conformant; }; /* Stuff that isn't used anywhere but is nice to pretty-print while @@ -1134,7 +1134,7 @@ int decode_edid(unsigned char *edid, int size, struct edid *out) .has_valid_range_descriptor = 1, .has_valid_max_dotclock = 1, .has_valid_string_termination = 1, - .conformant = 1, + .conformant = EDID_CONFORMANT, }; dump_breakdown(edid); @@ -1143,7 +1143,7 @@ int decode_edid(unsigned char *edid, int size, struct edid *out) if (!edid || memcmp(edid, "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", 8)) { printk(BIOS_SPEW, "No header found\n"); - return 1; + return EDID_ABSENT; } if (manufacturer_name(edid + 0x08)) @@ -1485,11 +1485,12 @@ int decode_edid(unsigned char *edid, int size, struct edid *out) if (c.nonconformant_digital_display || !c.has_valid_string_termination || !c.has_valid_descriptor_pad || - !c.has_preferred_timing) - c.conformant = 0; - if (!c.conformant) + !c.has_preferred_timing) { + c.conformant = EDID_NOT_CONFORMANT; printk(BIOS_ERR, "EDID block does NOT conform to EDID 1.4!\n"); + } + if (c.nonconformant_digital_display) printk(BIOS_ERR, "\tDigital display field contains garbage: %x\n", @@ -1507,7 +1508,7 @@ int decode_edid(unsigned char *edid, int size, struct edid *out) !c.has_valid_string_termination || !c.has_valid_descriptor_pad || !c.has_preferred_timing) { - c.conformant = 0; + c.conformant = EDID_NOT_CONFORMANT; } /** * According to E-EDID (EDIDv1.3), has_name_descriptor and @@ -1516,7 +1517,7 @@ int decode_edid(unsigned char *edid, int size, struct edid *out) * don't have them. As a workaround, we only print warning * messages. */ - if (!c.conformant) + if (c.conformant == EDID_NOT_CONFORMANT) printk(BIOS_ERR, "EDID block does NOT conform to EDID 1.3!\n"); else if (!c.has_name_descriptor || !c.has_range_descriptor) @@ -1542,11 +1543,11 @@ int decode_edid(unsigned char *edid, int size, struct edid *out) "\tDetailed block string not properly terminated\n"); } else if (c.claims_one_point_two) { if (c.nonconformant_digital_display || - !c.has_valid_string_termination) - c.conformant = 0; - if (!c.conformant) + !c.has_valid_string_termination) { + c.conformant = EDID_NOT_CONFORMANT; printk(BIOS_ERR, "EDID block does NOT conform to EDID 1.2!\n"); + } if (c.nonconformant_digital_display) printk(BIOS_ERR, "\tDigital display field contains garbage: %x\n", @@ -1555,11 +1556,11 @@ int decode_edid(unsigned char *edid, int size, struct edid *out) printk(BIOS_ERR, "\tDetailed block string not properly terminated\n"); } else if (c.claims_one_point_oh) { - if (c.seen_non_detailed_descriptor) - c.conformant = 0; - if (!c.conformant) + if (c.seen_non_detailed_descriptor) { + c.conformant = EDID_NOT_CONFORMANT; printk(BIOS_ERR, "EDID block does NOT conform to EDID 1.0!\n"); + } if (c.seen_non_detailed_descriptor) printk(BIOS_ERR, "\tHas descriptor blocks other than detailed timings\n"); @@ -1576,7 +1577,7 @@ int decode_edid(unsigned char *edid, int size, struct edid *out) !c.has_valid_descriptor_ordering || !c.has_valid_range_descriptor || !c.manufacturer_name_well_formed) { - c.conformant = 0; + c.conformant = EDID_NOT_CONFORMANT; printk(BIOS_ERR, "EDID block does not conform at all!\n"); if (c.nonconformant_extension) printk(BIOS_ERR, @@ -1618,7 +1619,7 @@ int decode_edid(unsigned char *edid, int size, struct edid *out) if (c.warning_zero_preferred_refresh) printk(BIOS_ERR, "Warning: CVT block does not set preferred refresh rate\n"); - return !c.conformant; + return c.conformant; } /* diff --git a/src/soc/nvidia/tegra124/dp.c b/src/soc/nvidia/tegra124/dp.c index a308f68fe1..0132369073 100644 --- a/src/soc/nvidia/tegra124/dp.c +++ b/src/soc/nvidia/tegra124/dp.c @@ -1322,7 +1322,7 @@ static void tegra_dp_update_config(struct tegra_dc_dp_data *dp, return; } - if (decode_edid(buf, sizeof(buf), &edid)) { + if (decode_edid(buf, sizeof(buf), &edid) != EDID_CONFORMANT) { printk(BIOS_ERR, "%s: Failed to decode EDID. Use defaults.\n", __func__); return; diff --git a/src/soc/nvidia/tegra210/dp.c b/src/soc/nvidia/tegra210/dp.c index e0475842e3..350eb8254d 100644 --- a/src/soc/nvidia/tegra210/dp.c +++ b/src/soc/nvidia/tegra210/dp.c @@ -1361,7 +1361,7 @@ static void tegra_dp_update_config(struct tegra_dc_dp_data *dp, return; } - if (decode_edid(buf, sizeof(buf), &edid)) { + if (decode_edid(buf, sizeof(buf), &edid) != EDID_CONFORMANT) { printk(BIOS_ERR, "%s: Failed to decode EDID. Use defaults.\n", __func__); return; diff --git a/src/soc/rockchip/common/edp.c b/src/soc/rockchip/common/edp.c index 5723ccf660..259400530e 100644 --- a/src/soc/rockchip/common/edp.c +++ b/src/soc/rockchip/common/edp.c @@ -778,7 +778,7 @@ static int rk_edp_read_edid(struct rk_edp *edp, struct edid *edid) } } - if (decode_edid(buf, edid_size, edid)) { + if (decode_edid(buf, edid_size, edid) != EDID_CONFORMANT) { printk(BIOS_ERR, "%s: Failed to decode EDID.\n", __func__); return -1; diff --git a/src/soc/rockchip/rk3288/hdmi.c b/src/soc/rockchip/rk3288/hdmi.c index 496629316e..5e744236e7 100644 --- a/src/soc/rockchip/rk3288/hdmi.c +++ b/src/soc/rockchip/rk3288/hdmi.c @@ -814,7 +814,7 @@ int rk_hdmi_get_edid(struct edid *edid) /* Assume usage of HDMI implies an external display in which case * we should be lenient about errors that the EDID decoder finds. */ - if (decode_edid(edid_buf, edid_size, edid)) + if (decode_edid(edid_buf, edid_size, edid) != EDID_CONFORMANT) hdmi_debug("failed to decode edid.\n"); /* Try 480p for best compatibility. */