From patchwork Tue Oct 26 21:56:48 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Philip Chen X-Patchwork-Id: 12585731 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id BA326C433EF for ; Tue, 26 Oct 2021 21:56:57 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7358760F9B for ; Tue, 26 Oct 2021 21:56:57 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 7358760F9B Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=chromium.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 20D9A89D6C; Tue, 26 Oct 2021 21:56:56 +0000 (UTC) Received: from mail-pl1-x62c.google.com (mail-pl1-x62c.google.com [IPv6:2607:f8b0:4864:20::62c]) by gabe.freedesktop.org (Postfix) with ESMTPS id 8723789D6C for ; Tue, 26 Oct 2021 21:56:54 +0000 (UTC) Received: by mail-pl1-x62c.google.com with SMTP id c4so503145plg.13 for ; Tue, 26 Oct 2021 14:56:54 -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:mime-version :content-transfer-encoding; bh=pRigxBz5/D3sM7hIYu1MI2WLoqxA+czuJ/L/Y38MXO0=; b=lcxOsgy7teqgmFS1ET+i4GO8tk8jJZK2l3b3NNmXTUJEOOeyIR9ww+u8wAPVlKq3E8 9u2UyNIpoWmWOuV6016YyQcQ29gFEKq85ml8ZX/G0XswgOB9XMoou9+CIlD0MMAeQy9u wm8GDa8kolfMCTHiId4pHIyQ+4CurNYdePQ7c= 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:mime-version :content-transfer-encoding; bh=pRigxBz5/D3sM7hIYu1MI2WLoqxA+czuJ/L/Y38MXO0=; b=EBEp3KDaHTdV1x3czDsMYi7mIlennmMZDghxDoGquXFy5/QNzXYbZx3K85OoDhN5kA A7JqMCoyWYkIuQZPWynL6zK1sS6uCoKlChqmLkZzZK8q6WDk14u7C59biVtptasMuXrX 6xyI53+T+zPwY/eKERMshoDRUGV+N+tkXEywb+bfBDRWDP6B4ufXYPgIzgWbkmFTfgPh FviUcXuNM8/EW6T6BCNSXYniiPPS9CMspehirAjj83gSnHuWntKyYYHv/3aG4HEWLNkx l8wiOVgdyXBXAcT9R54sb0xKeIH8+KcI3EXgBlOu2V2myIaT0rLgkV2goSVHGef9oueK +xNA== X-Gm-Message-State: AOAM533MN8Un8nhDd9GA6HiRoI88OQ0GVtlwAwOCWnk666Sa+K6YbLu4 g2Wcc8XpGOsx97dEXFSgRspfwA== X-Google-Smtp-Source: ABdhPJzxbfRRmIUWZ60dak+jkyhz6ZtN3XK5+XUHyHqzaiubi/KurftS/TZD+EZgDHtoToUKW6tfMA== X-Received: by 2002:a17:902:f686:b0:140:3913:8342 with SMTP id l6-20020a170902f68600b0014039138342mr20452927plg.43.1635285413984; Tue, 26 Oct 2021 14:56:53 -0700 (PDT) Received: from philipchen.mtv.corp.google.com ([2620:15c:202:201:dad:6684:6674:b268]) by smtp.gmail.com with ESMTPSA id t8sm21225953pgk.66.2021.10.26.14.56.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 Oct 2021 14:56:53 -0700 (PDT) From: Philip Chen To: LKML Cc: swboyd@chromium.org, dianders@chromium.org, Philip Chen , Andrzej Hajda , Daniel Vetter , David Airlie , Jernej Skrabec , Jonas Karlman , Laurent Pinchart , Neil Armstrong , Robert Foss , dri-devel@lists.freedesktop.org Subject: [PATCH v4 1/2] drm/bridge: parade-ps8640: Enable runtime power management Date: Tue, 26 Oct 2021 14:56:48 -0700 Message-Id: <20211026145622.v4.1.I9d81c3b44f350707b5373d00524af77c4aae862b@changeid> X-Mailer: git-send-email 2.33.0.1079.g6e70778dc9-goog MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Fit ps8640 driver into runtime power management framework: First, break _poweron() to 3 parts: (1) turn on power and wait for ps8640's internal MCU to finish init (2) check panel HPD (which is proxied by GPIO9) (3) the other configs. As runtime_resume() can be called before panel is powered, we only add (1) to _resume() and leave (2)(3) to _pre_enable(). We also add (2) to _aux_transfer() as we want to ensure panel HPD is asserted before we start AUX CH transactions. Second, the original driver has a mysterious delay of 50 ms between (2) and (3). Since Parade's support can't explain what the delay is for, and we don't see removing the delay break any boards at hand, remove the delay to fit into this driver change. In addition, rename "powered" to "pre_enabled" and don't check for it in the pm_runtime calls. The pm_runtime calls are already refcounted so there's no reason to check there. The other user of "powered", _get_edid(), only cares if pre_enable() has already been called. Lastly, change some existing DRM_...() logging to dev_...() along the way, since DRM_...() seem to be deprecated in [1]. [1] https://patchwork.freedesktop.org/patch/454760/ Signed-off-by: Philip Chen Reviewed-by: Douglas Anderson Reviewed-by: Stephen Boyd --- In v3, I also added pm_suspend_ignore_children() in the ps8640_probe() but forgot to mention that in the v3 change log. Changes in v4: - Make ps8640_ensure_hpd() return int (This change was mis-added to another patch [2] in this patch series: [2] https://patchwork.kernel.org/project/dri-devel/patch/20211026121058.v3.2.I09899dea340f11feab97d719cb4b62bef3179e4b@changeid/) Changes in v3: - Fix typo/wording in the commit message. - Add ps8640_aux_transfer_msg() for AUX operation. In ps8640_aux_transfer(), wrap around ps8640_aux_transfer_msg() with PM operations and HPD check. - Document why autosuspend_delay is set to 500ms. drivers/gpu/drm/bridge/parade-ps8640.c | 186 +++++++++++++++---------- 1 file changed, 115 insertions(+), 71 deletions(-) diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c index 3aaa90913bf8..cf1f630a3958 100644 --- a/drivers/gpu/drm/bridge/parade-ps8640.c +++ b/drivers/gpu/drm/bridge/parade-ps8640.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -100,7 +101,7 @@ struct ps8640 { struct regulator_bulk_data supplies[2]; struct gpio_desc *gpio_reset; struct gpio_desc *gpio_powerdown; - bool powered; + bool pre_enabled; }; static const struct regmap_config ps8640_regmap_config[] = { @@ -148,8 +149,29 @@ static inline struct ps8640 *aux_to_ps8640(struct drm_dp_aux *aux) return container_of(aux, struct ps8640, aux); } -static ssize_t ps8640_aux_transfer(struct drm_dp_aux *aux, - struct drm_dp_aux_msg *msg) +static int ps8640_ensure_hpd(struct ps8640 *ps_bridge) +{ + struct regmap *map = ps_bridge->regmap[PAGE2_TOP_CNTL]; + struct device *dev = &ps_bridge->page[PAGE2_TOP_CNTL]->dev; + int status; + int ret; + + /* + * Apparently something about the firmware in the chip signals that + * HPD goes high by reporting GPIO9 as high (even though HPD isn't + * actually connected to GPIO9). + */ + ret = regmap_read_poll_timeout(map, PAGE2_GPIO_H, status, + status & PS_GPIO9, 20 * 1000, 200 * 1000); + + if (ret < 0) + dev_warn(dev, "HPD didn't go high: %d\n", ret); + + return ret; +} + +static ssize_t ps8640_aux_transfer_msg(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) { struct ps8640 *ps_bridge = aux_to_ps8640(aux); struct regmap *map = ps_bridge->regmap[PAGE0_DP_CNTL]; @@ -274,38 +296,49 @@ static ssize_t ps8640_aux_transfer(struct drm_dp_aux *aux, return len; } -static int ps8640_bridge_vdo_control(struct ps8640 *ps_bridge, - const enum ps8640_vdo_control ctrl) +static ssize_t ps8640_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct ps8640 *ps_bridge = aux_to_ps8640(aux); + struct device *dev = &ps_bridge->page[PAGE0_DP_CNTL]->dev; + int ret; + + pm_runtime_get_sync(dev); + ret = ps8640_ensure_hpd(ps_bridge); + if (!ret) + ret = ps8640_aux_transfer_msg(aux, msg); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return ret; +} + +static void ps8640_bridge_vdo_control(struct ps8640 *ps_bridge, + const enum ps8640_vdo_control ctrl) { struct regmap *map = ps_bridge->regmap[PAGE3_DSI_CNTL1]; + struct device *dev = &ps_bridge->page[PAGE3_DSI_CNTL1]->dev; u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, ctrl }; int ret; ret = regmap_bulk_write(map, PAGE3_SET_ADD, vdo_ctrl_buf, sizeof(vdo_ctrl_buf)); - if (ret < 0) { - DRM_ERROR("failed to %sable VDO: %d\n", - ctrl == ENABLE ? "en" : "dis", ret); - return ret; - } - - return 0; + if (ret < 0) + dev_err(dev, "failed to %sable VDO: %d\n", + ctrl == ENABLE ? "en" : "dis", ret); } -static void ps8640_bridge_poweron(struct ps8640 *ps_bridge) +static int __maybe_unused ps8640_resume(struct device *dev) { - struct regmap *map = ps_bridge->regmap[PAGE2_TOP_CNTL]; - int ret, status; - - if (ps_bridge->powered) - return; + struct ps8640 *ps_bridge = dev_get_drvdata(dev); + int ret; ret = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies), ps_bridge->supplies); if (ret < 0) { - DRM_ERROR("cannot enable regulators %d\n", ret); - return; + dev_err(dev, "cannot enable regulators %d\n", ret); + return ret; } gpiod_set_value(ps_bridge->gpio_powerdown, 0); @@ -314,86 +347,78 @@ static void ps8640_bridge_poweron(struct ps8640 *ps_bridge) gpiod_set_value(ps_bridge->gpio_reset, 0); /* - * Wait for the ps8640 embedded MCU to be ready - * First wait 200ms and then check the MCU ready flag every 20ms + * Mystery 200 ms delay for the "MCU to be ready". It's unclear if + * this is truly necessary since the MCU will already signal that + * things are "good to go" by signaling HPD on "gpio 9". See + * ps8640_ensure_hpd(). For now we'll keep this mystery delay just in + * case. */ msleep(200); - ret = regmap_read_poll_timeout(map, PAGE2_GPIO_H, status, - status & PS_GPIO9, 20 * 1000, 200 * 1000); - - if (ret < 0) { - DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", ret); - goto err_regulators_disable; - } - - msleep(50); - - /* - * The Manufacturer Command Set (MCS) is a device dependent interface - * intended for factory programming of the display module default - * parameters. Once the display module is configured, the MCS shall be - * disabled by the manufacturer. Once disabled, all MCS commands are - * ignored by the display interface. - */ - - ret = regmap_update_bits(map, PAGE2_MCS_EN, MCS_EN, 0); - if (ret < 0) { - DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret); - goto err_regulators_disable; - } - - /* Switch access edp panel's edid through i2c */ - ret = regmap_write(map, PAGE2_I2C_BYPASS, I2C_BYPASS_EN); - if (ret < 0) { - DRM_ERROR("failed write PAGE2_I2C_BYPASS: %d\n", ret); - goto err_regulators_disable; - } - - ps_bridge->powered = true; - - return; - -err_regulators_disable: - regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies), - ps_bridge->supplies); + return 0; } -static void ps8640_bridge_poweroff(struct ps8640 *ps_bridge) +static int __maybe_unused ps8640_suspend(struct device *dev) { + struct ps8640 *ps_bridge = dev_get_drvdata(dev); int ret; - if (!ps_bridge->powered) - return; - gpiod_set_value(ps_bridge->gpio_reset, 1); gpiod_set_value(ps_bridge->gpio_powerdown, 1); ret = regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies), ps_bridge->supplies); if (ret < 0) - DRM_ERROR("cannot disable regulators %d\n", ret); + dev_err(dev, "cannot disable regulators %d\n", ret); - ps_bridge->powered = false; + return ret; } +static const struct dev_pm_ops ps8640_pm_ops = { + SET_RUNTIME_PM_OPS(ps8640_suspend, ps8640_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + static void ps8640_pre_enable(struct drm_bridge *bridge) { struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); + struct regmap *map = ps_bridge->regmap[PAGE2_TOP_CNTL]; + struct device *dev = &ps_bridge->page[PAGE0_DP_CNTL]->dev; int ret; - ps8640_bridge_poweron(ps_bridge); + pm_runtime_get_sync(dev); + ps8640_ensure_hpd(ps_bridge); + + /* + * The Manufacturer Command Set (MCS) is a device dependent interface + * intended for factory programming of the display module default + * parameters. Once the display module is configured, the MCS shall be + * disabled by the manufacturer. Once disabled, all MCS commands are + * ignored by the display interface. + */ + + ret = regmap_update_bits(map, PAGE2_MCS_EN, MCS_EN, 0); + if (ret < 0) + dev_warn(dev, "failed write PAGE2_MCS_EN: %d\n", ret); - ret = ps8640_bridge_vdo_control(ps_bridge, ENABLE); + /* Switch access edp panel's edid through i2c */ + ret = regmap_write(map, PAGE2_I2C_BYPASS, I2C_BYPASS_EN); if (ret < 0) - ps8640_bridge_poweroff(ps_bridge); + dev_warn(dev, "failed write PAGE2_MCS_EN: %d\n", ret); + + ps8640_bridge_vdo_control(ps_bridge, ENABLE); + + ps_bridge->pre_enabled = true; } static void ps8640_post_disable(struct drm_bridge *bridge) { struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); + ps_bridge->pre_enabled = false; + ps8640_bridge_vdo_control(ps_bridge, DISABLE); - ps8640_bridge_poweroff(ps_bridge); + pm_runtime_put_sync_suspend(&ps_bridge->page[PAGE0_DP_CNTL]->dev); } static int ps8640_bridge_attach(struct drm_bridge *bridge, @@ -474,7 +499,7 @@ static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge, struct drm_connector *connector) { struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); - bool poweroff = !ps_bridge->powered; + bool poweroff = !ps_bridge->pre_enabled; struct edid *edid; /* @@ -512,6 +537,12 @@ static const struct drm_bridge_funcs ps8640_bridge_funcs = { .pre_enable = ps8640_pre_enable, }; +static void ps8640_runtime_disable(void *data) +{ + pm_runtime_dont_use_autosuspend(data); + pm_runtime_disable(data); +} + static int ps8640_probe(struct i2c_client *client) { struct device *dev = &client->dev; @@ -587,6 +618,18 @@ static int ps8640_probe(struct i2c_client *client) ps_bridge->aux.transfer = ps8640_aux_transfer; drm_dp_aux_init(&ps_bridge->aux); + pm_runtime_enable(dev); + /* + * In practice, ps8640_aux_transfer_msg() takes ~300ms to complete in + * the worst case. Set autosuspend_delay to 500ms. + */ + pm_runtime_set_autosuspend_delay(dev, 500); + pm_runtime_use_autosuspend(dev); + pm_suspend_ignore_children(dev, true); + ret = devm_add_action_or_reset(dev, ps8640_runtime_disable, dev); + if (ret) + return ret; + drm_bridge_add(&ps_bridge->bridge); return 0; @@ -613,6 +656,7 @@ static struct i2c_driver ps8640_driver = { .driver = { .name = "ps8640", .of_match_table = ps8640_match, + .pm = &ps8640_pm_ops, }, }; module_i2c_driver(ps8640_driver); From patchwork Tue Oct 26 21:56:49 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Philip Chen X-Patchwork-Id: 12585733 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id BC7D0C433F5 for ; Tue, 26 Oct 2021 21:57:03 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 804AB60FE8 for ; Tue, 26 Oct 2021 21:57:03 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 804AB60FE8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=chromium.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id D5E1989E52; Tue, 26 Oct 2021 21:57:00 +0000 (UTC) Received: from mail-pl1-x636.google.com (mail-pl1-x636.google.com [IPv6:2607:f8b0:4864:20::636]) by gabe.freedesktop.org (Postfix) with ESMTPS id DA4CF89D6C for ; Tue, 26 Oct 2021 21:56:55 +0000 (UTC) Received: by mail-pl1-x636.google.com with SMTP id z11so522397plg.8 for ; Tue, 26 Oct 2021 14:56:55 -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=9F+EWbh01K9eqvh7QO6VrhctGso+L9ps7sX+i8thX2Y=; b=Zdc4ztOZkl8MtmXXDulYtc8GEdI8IyMPqz3rieEXFQnL2Lqi1V7RuMN7H7cBLLh/WM /MIdKBeNWbepPud2CCiph86WRpuM3I7XKcdT+TO34XWvl8qHH7qYkb7bMs3S+fds2i43 aGu4iuDM+PHXHHNwIcrFMr7ZDDW4/ailCSjR8= 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=9F+EWbh01K9eqvh7QO6VrhctGso+L9ps7sX+i8thX2Y=; b=vU33h0ayGrwTnT4KwhW2Mt1giR4cDWSw8y0tQ1zESe/QGcWgNK/nRMZ34Fyo49mYbw RpitCB8UjcE83oVf19CmODkeIP3ujyThkKAC3MKs4XHZMtSrngFwU+mshDq6rG0hQyo3 0uraQ1h2iVLllA4qhD5SpFwXPJEc/4SRh6HRy1UAhiMlBEIeLjdVwDAJ0V9BHDJLdHbs KGMGLNX9xNARbqZIH3bNQ9K60uCbJSjRDBHopOuaflmawh2beUxXhYqblTUqCWrcimtf cat0nwA2zhSB7lEQotb4C4KoGhyOPd5Pnisanqp7V57s3OSc9Od2K31Uh+AvbPg92nJW OYzA== X-Gm-Message-State: AOAM533Jdy7UG0+Zv1xQlDifVUZVDnw04Ktj4rcunlHaRo+M04I4fq9L TYkYIPjAg5nGgf3Vws7n4/yUTqTx490EJQ== X-Google-Smtp-Source: ABdhPJzf1EEFbnTBWOPKTGgp7zivHRUhUNIS7IywoMnYJmw7DzXLac4ndmz27S1IJS0Os/VTjullCA== X-Received: by 2002:a17:90b:198b:: with SMTP id mv11mr1503430pjb.235.1635285415549; Tue, 26 Oct 2021 14:56:55 -0700 (PDT) Received: from philipchen.mtv.corp.google.com ([2620:15c:202:201:dad:6684:6674:b268]) by smtp.gmail.com with ESMTPSA id t8sm21225953pgk.66.2021.10.26.14.56.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 Oct 2021 14:56:55 -0700 (PDT) From: Philip Chen To: LKML Cc: swboyd@chromium.org, dianders@chromium.org, Philip Chen , Andrzej Hajda , Daniel Vetter , David Airlie , Jernej Skrabec , Jonas Karlman , Laurent Pinchart , Neil Armstrong , Robert Foss , dri-devel@lists.freedesktop.org Subject: [PATCH v4 2/2] drm/bridge: parade-ps8640: Populate devices on aux-bus Date: Tue, 26 Oct 2021 14:56:49 -0700 Message-Id: <20211026145622.v4.2.I09899dea340f11feab97d719cb4b62bef3179e4b@changeid> X-Mailer: git-send-email 2.33.0.1079.g6e70778dc9-goog In-Reply-To: <20211026145622.v4.1.I9d81c3b44f350707b5373d00524af77c4aae862b@changeid> References: <20211026145622.v4.1.I9d81c3b44f350707b5373d00524af77c4aae862b@changeid> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Conventionally, panel is listed under the root of the device tree. When userland asks for display mode, ps8640 bridge is responsible for returning EDID when ps8640_bridge_get_edid() is called. Now enable a new option of listing panel under "aux-bus" of ps8640 bridge node in the device tree. In this case, panel driver can retrieve EDID by triggering AUX transactions, without ps8640_bridge_get_edid() calls at all. To prevent the "old" and "new" options from interfering with each other's logic flow, disable DRM_BRIDGE_OP_EDID when the new option is taken. Signed-off-by: Philip Chen Reviewed-by: Stephen Boyd Reviewed-by: Douglas Anderson --- (no changes since v3) Changes in v3: - Fix when to call of_node_put() in ps8640_of_panel_on_aux_bus() Changes in v2: - Add of_node_put() calls in ps8640_of_panel_on_aux_bus() - Select DRM_DP_AUX_BUS for PS8640 driver in Kconfig - Replace _put_sync() with _put_sync_suspend() in ps8640_post_disable() drivers/gpu/drm/bridge/Kconfig | 1 + drivers/gpu/drm/bridge/parade-ps8640.c | 51 ++++++++++++++++++++------ 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 431b6e12a81f..61db5a66b493 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -182,6 +182,7 @@ config DRM_PARADE_PS8622 config DRM_PARADE_PS8640 tristate "Parade PS8640 MIPI DSI to eDP Converter" depends on OF + select DRM_DP_AUX_BUS select DRM_KMS_HELPER select DRM_MIPI_DSI select DRM_PANEL diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c index cf1f630a3958..e737f1a27f30 100644 --- a/drivers/gpu/drm/bridge/parade-ps8640.c +++ b/drivers/gpu/drm/bridge/parade-ps8640.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -149,6 +150,23 @@ static inline struct ps8640 *aux_to_ps8640(struct drm_dp_aux *aux) return container_of(aux, struct ps8640, aux); } +static bool ps8640_of_panel_on_aux_bus(struct device *dev) +{ + struct device_node *bus, *panel; + + bus = of_get_child_by_name(dev->of_node, "aux-bus"); + if (!bus) + return false; + + panel = of_get_child_by_name(bus, "panel"); + of_node_put(bus); + if (!panel) + return false; + of_node_put(panel); + + return true; +} + static int ps8640_ensure_hpd(struct ps8640 *ps_bridge) { struct regmap *map = ps_bridge->regmap[PAGE2_TOP_CNTL]; @@ -556,17 +574,6 @@ static int ps8640_probe(struct i2c_client *client) if (!ps_bridge) return -ENOMEM; - /* port@1 is ps8640 output port */ - ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL); - if (ret < 0) - return ret; - if (!panel) - return -ENODEV; - - ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel); - if (IS_ERR(ps_bridge->panel_bridge)) - return PTR_ERR(ps_bridge->panel_bridge); - ps_bridge->supplies[0].supply = "vdd33"; ps_bridge->supplies[1].supply = "vdd12"; ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies), @@ -589,9 +596,16 @@ static int ps8640_probe(struct i2c_client *client) ps_bridge->bridge.funcs = &ps8640_bridge_funcs; ps_bridge->bridge.of_node = dev->of_node; - ps_bridge->bridge.ops = DRM_BRIDGE_OP_EDID; ps_bridge->bridge.type = DRM_MODE_CONNECTOR_eDP; + /* + * In the device tree, if panel is listed under aux-bus of the bridge + * node, panel driver should be able to retrieve EDID by itself using + * aux-bus. So let's not set DRM_BRIDGE_OP_EDID here. + */ + if (!ps8640_of_panel_on_aux_bus(&client->dev)) + ps_bridge->bridge.ops = DRM_BRIDGE_OP_EDID; + ps_bridge->page[PAGE0_DP_CNTL] = client; ps_bridge->regmap[PAGE0_DP_CNTL] = devm_regmap_init_i2c(client, ps8640_regmap_config); @@ -630,6 +644,19 @@ static int ps8640_probe(struct i2c_client *client) if (ret) return ret; + devm_of_dp_aux_populate_ep_devices(&ps_bridge->aux); + + /* port@1 is ps8640 output port */ + ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL); + if (ret < 0) + return ret; + if (!panel) + return -ENODEV; + + ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel); + if (IS_ERR(ps_bridge->panel_bridge)) + return PTR_ERR(ps_bridge->panel_bridge); + drm_bridge_add(&ps_bridge->bridge); return 0;