Received: by 2002:a05:6a10:eb17:0:0:0:0 with SMTP id hx23csp864805pxb; Thu, 9 Sep 2021 14:04:06 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyl1FUrZYlUpI75NuraJ6Y5XK27gedEyt1fQKKCosV6eRfadEL4HLbFXblvTsItVKcTmRNf X-Received: by 2002:a92:c80e:: with SMTP id v14mr3890687iln.57.1631221446033; Thu, 09 Sep 2021 14:04:06 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1631221446; cv=none; d=google.com; s=arc-20160816; b=u3B3vvlayN4J263t/RbW1vuZiRloUzu7eqWr1sC+7+i8wmM0EeQ4w2OMJwtPLYpcFs QcYkUV+xytBhGWYptHb+XOyEsZuDhZ/GYPbCrEj7X3bX4IXZ2UkTGZ/Xg20lR/TFTLfa Hs3CYwk8CCY3WCztA/PXix+q0xKIgZVm6/0JQbsqCHq1iNrWMW3aJegAm3ABZcuKBlZx jBJN5XDpyd+zNHvLMGQlcDcr23w3WBCYnazW8vM2u/m73aXX+EI9Jjyb98pT30eaRGpj xIfC4ImgswPchPxRbGQl4Ex+47u8MGrXQuOrRsIbB8N3D5Su6jZCREK/8QJtFObipxxG P2AQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=wgdd7k2meN+TTX6Jg3GzgzE7H76ZLGquQVy1sMGiGZ4=; b=FrgHwtlxshWbmUXzeQwgh6rGr/s4NTP2CKR3e3lRitnWvH0qX8wxZwINdJzjDNiCvQ UIOEwBExGomWi3wPVzdF7ux/nbArT7PLccKNnxyMh/cGhRn3RES1a8Ds4fJmPzbNMWi7 +rz8yQ39o8HGPXVCjQjWJ6fJRazePF5wlgaIObEQFCnr5BvxEzaVmA/xMXEGpQnQ5imt RqOGrCYjBegOzMa8/OldBHBo/QwEy1/cjVGZrWfoBGs3lBlOMtu2dw9FhDt1huA20YUl rdD9FcLiceQq0Bg+xyYTWNL5rY93LDzOzmREQKXiQwKW82/iQS9xlLIdktaJQygJ7Zcf 5QYA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=MGMmmuxN; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id t22si3107307iom.43.2021.09.09.14.03.48; Thu, 09 Sep 2021 14:04:06 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=MGMmmuxN; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1346720AbhIIVCp (ORCPT + 99 others); Thu, 9 Sep 2021 17:02:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50036 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1346155AbhIIVCe (ORCPT ); Thu, 9 Sep 2021 17:02:34 -0400 Received: from mail-pg1-x533.google.com (mail-pg1-x533.google.com [IPv6:2607:f8b0:4864:20::533]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5AB07C0613D9 for ; Thu, 9 Sep 2021 14:01:24 -0700 (PDT) Received: by mail-pg1-x533.google.com with SMTP id e7so3117505pgk.2 for ; Thu, 09 Sep 2021 14:01:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=wgdd7k2meN+TTX6Jg3GzgzE7H76ZLGquQVy1sMGiGZ4=; b=MGMmmuxNGOl5nA2L8i1UACBEDd+APufRbYL5wqzKPPpNcAV+1Zp4qsTrTzUuWBhYNZ RW6cG6JJAeckRKgjnRag/Gb6VdL6aoK0eVIAGWiXcKioTmZIswINTzMBt24Ov/kf5Q8w VxpkJRryXxXMQGR+R6bHJ/Q1IWToWdEMQPgwo= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=wgdd7k2meN+TTX6Jg3GzgzE7H76ZLGquQVy1sMGiGZ4=; b=YAW9c5mWA4DJH00O7/y5jIGH9a8XZzZso1chWbAR9SJ3JF+mS/89BcWbNl9n3779CT /oscCv3yowal6g8nvOBl/EpuMRHGvDv/YqIQBdPoirBFqgKs6sH0xU3l98tw4eNQuVw0 7ppA1vrcIL6Z5b6kUirml7s5pFFFY7moP607ZKlRv8cFhzo2Q/ZUgDBu98hBXErMKRTw UI3+9/HZBqdhWF3wV4xZjpEQ2E3SWbcy0rRz9R995FEEQbTMus24vRNKaPaKfwE3OHyD 0MRG2ku/WtiNXMnawWSH6HfrP9FhRt2P9dCinZhwiNeDWXOzbGOFKU9a2A3aGOvDSKmC 83hQ== X-Gm-Message-State: AOAM530lzG7Ks4Ml4NYpAn5OCitz5WxtByLNvJvzlSaRh196hVj7NoXZ lq1E3sugHAGgAuiSN38l3h9QUw== X-Received: by 2002:a63:2d07:: with SMTP id t7mr4411763pgt.101.1631221283830; Thu, 09 Sep 2021 14:01:23 -0700 (PDT) Received: from tictac2.mtv.corp.google.com ([2620:15c:202:201:8da3:b0fb:4261:2c10]) by smtp.gmail.com with ESMTPSA id l143sm177069pfd.60.2021.09.09.14.01.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 09 Sep 2021 14:01:23 -0700 (PDT) From: Douglas Anderson To: Thierry Reding , Rob Herring , Sam Ravnborg Cc: devicetree@vger.kernel.org, Maxime Ripard , Thomas Zimmermann , Linus W , Daniel Vetter , linux-arm-msm@vger.kernel.org, Steev Klimaszewski , Maarten Lankhorst , Bjorn Andersson , David Airlie , dri-devel@lists.freedesktop.org, Douglas Anderson , linux-kernel@vger.kernel.org Subject: [PATCH v4 03/15] drm/edid: Allow querying/working with the panel ID from the EDID Date: Thu, 9 Sep 2021 14:00:19 -0700 Message-Id: <20210909135838.v4.3.I4a672175ba1894294d91d3dbd51da11a8239cf4a@changeid> X-Mailer: git-send-email 2.33.0.309.g3052b89438-goog In-Reply-To: <20210909210032.465570-1-dianders@chromium.org> References: <20210909210032.465570-1-dianders@chromium.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org EDIDs have 32-bits worth of data which is intended to be used to uniquely identify the make/model of a panel. This has historically been used only internally in the EDID processing code to identify quirks with panels. We'd like to use this panel ID in panel drivers to identify which panel is hooked up and from that information figure out power sequence timings. Let's expose this information from the EDID code and also allow it to be accessed early, before a connector has been created. To make matching in the panel drivers code easier, we'll return the panel ID as a 32-bit value. We'll provide some functions for converting this value back and forth to something more human readable. Signed-off-by: Douglas Anderson Acked-by: Sam Ravnborg --- Changes in v4: - Don't refer to "panel-simple" in commit message. - decode_edid_id() => drm_edid_decode_panel_id() - drm_do_get_edid_blk0() => drm_do_get_edid_base_block() - drm_get_panel_id() => drm_edid_get_panel_id() - encode_edid_id() => drm_edid_encode_panel_id() - split panel id extraction out to its own function. Changes in v3: - Decode hex product ID w/ same endianness as everyone else. drivers/gpu/drm/drm_edid.c | 67 ++++++++++++++++++++++++++++++++++++++ include/drm/drm_edid.h | 47 ++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) 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 diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index deccfd39e6db..4d17cd04fff7 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -508,6 +508,52 @@ static inline u8 drm_eld_get_conn_type(const uint8_t *eld) return eld[DRM_ELD_SAD_COUNT_CONN_TYPE] & DRM_ELD_CONN_TYPE_MASK; } +/** + * drm_edid_encode_panel_id - Encode an ID for matching against drm_edid_get_panel_id() + * @vend_chr_0: First character of the vendor string. + * @vend_chr_2: Second character of the vendor string. + * @vend_chr_3: Third character of the vendor string. + * @product_id: The 16-bit product ID. + * + * This is a macro so that it can be calculated at compile time and used + * as an initializer. + * + * For instance: + * drm_edid_encode_panel_id('B', 'O', 'E', 0x2d08) => 0x09e52d08 + * + * Return: a 32-bit ID per panel. + */ +#define drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, vend_chr_2, product_id) \ + ((((u32)(vend_chr_0) - '@') & 0x1f) << 26 | \ + (((u32)(vend_chr_1) - '@') & 0x1f) << 21 | \ + (((u32)(vend_chr_2) - '@') & 0x1f) << 16 | \ + ((product_id) & 0xffff)) + +/** + * drm_edid_decode_panel_id - Decode a panel ID from drm_edid_encode_panel_id() + * @panel_id: The panel ID to decode. + * @vend: A 4-byte buffer to store the 3-letter vendor string plus a '\0' + * termination + * @product_id: The product ID will be returned here. + * + * For instance, after: + * drm_edid_decode_panel_id(0x09e52d08, vend, &product_id) + * These will be true: + * vend[0] = 'B' + * vend[1] = 'O' + * vend[2] = 'E' + * vend[3] = '\0' + * product_id = 0x2d08 + */ +static inline void drm_edid_decode_panel_id(u32 panel_id, char vend[4], u16 *product_id) +{ + *product_id = (u16)(panel_id & 0xffff); + vend[0] = '@' + ((panel_id >> 26) & 0x1f); + vend[1] = '@' + ((panel_id >> 21) & 0x1f); + vend[2] = '@' + ((panel_id >> 16) & 0x1f); + vend[3] = '\0'; +} + bool drm_probe_ddc(struct i2c_adapter *adapter); struct edid *drm_do_get_edid(struct drm_connector *connector, int (*get_edid_block)(void *data, u8 *buf, unsigned int block, @@ -515,6 +561,7 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, void *data); struct edid *drm_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter); +u32 drm_edid_get_panel_id(struct i2c_adapter *adapter); struct edid *drm_get_edid_switcheroo(struct drm_connector *connector, struct i2c_adapter *adapter); struct edid *drm_edid_duplicate(const struct edid *edid); -- 2.33.0.309.g3052b89438-goog