diff options
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 520fe1391769..f84e0dd264f4 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2087,6 +2087,73 @@ struct edid *drm_get_edid(struct drm_connector *connector, } EXPORT_SYMBOL(drm_get_edid); +static u32 edid_extract_panel_id(const struct edid *edid) +{ + /* + * In theory we could try to de-obfuscate this like edid_get_quirks() + * does, but it's easier to just deal with a 32-bit number since then + * it can be compared with "==". + * + * NOTE that we deal with endianness differently for the top half + * of this ID than for the bottom half. The bottom half (the product + * id) gets decoded as little endian by the EDID_PRODUCT_ID because + * that's how everyone seems to interpret it. The top half (the mfg_id) + * gets stored as big endian because that makes + * drm_edid_encode_panel_id() and drm_edid_decode_panel_id() easier + * to write (it's easier to extract the ASCII). It doesn't really + * matter, though, as long as the number here is unique. + */ + return (u32)edid->mfg_id[0] << 24 | + (u32)edid->mfg_id[1] << 16 | + (u32)EDID_PRODUCT_ID(edid); +} + +/** + * drm_edid_get_panel_id - Get a panel's ID through DDC + * @adapter: I2C adapter to use for DDC + * + * This function reads the first block of the EDID of a panel and (assuming + * that the EDID is valid) extracts the ID out of it. The ID is a 32-bit value + * (16 bits of manufacturer ID and 16 bits of per-manufacturer ID) that's + * supposed to be different for each different modem of panel. + * + * This function is intended to be used during early probing on devices where + * more than one panel might be present. Because of its intended use it must + * assume that the EDID of the panel is correct, at least as far as the ID + * is concerned (in other words, we don't process any overrides here). + * + * NOTE: it's expected that this function and drm_do_get_edid() will both + * be read the EDID, but there is no caching between them. Since we're only + * reading the first block, hopefully this extra overhead won't be too big. + * + * Return: A 32-bit ID that should be different for each make/model of panel. + * See the functions drm_edid_encode_panel_id() and + * drm_edid_decode_panel_id() for some details on the structure of this + * ID. + */ + +u32 drm_edid_get_panel_id(struct i2c_adapter *adapter) +{ + struct edid *edid; + u32 panel_id; + + edid = drm_do_get_edid_base_block(drm_do_probe_ddc_edid, adapter, + NULL, NULL); + + /* + * There are no manufacturer IDs of 0, so if there is a problem reading + * the EDID then we'll just return 0. + */ + if (IS_ERR_OR_NULL(edid)) + return 0; + + panel_id = edid_extract_panel_id(edid); + kfree(edid); + + return panel_id; +} +EXPORT_SYMBOL(drm_edid_get_panel_id); + /** * drm_get_edid_switcheroo - get EDID data for a vga_switcheroo output * @connector: connector we're probing |