Received: by 2002:a05:6a10:a0d1:0:0:0:0 with SMTP id j17csp864447pxa; Sat, 22 Aug 2020 02:54:20 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwLlUB6HQrE4pkiIYclapCnq6c1gFwmdGC8Of/YqgPbAs2ToOqHTc/fuvs3gd3Lpq5Imqb4 X-Received: by 2002:a17:906:68b:: with SMTP id u11mr7162834ejb.143.1598090060234; Sat, 22 Aug 2020 02:54:20 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1598090060; cv=none; d=google.com; s=arc-20160816; b=gwDfKiNPC1bqlq4EgozJDG2LYrW6PdJMIkWx4s0MDXDzY45B3OxBel0LwbwxW+RTIN wNMcF8Kb03OHGs5N0pmoz1ZLDWCDK9PAptvLiXWfuxfd/YRmBlXx4ej2OBcDcuADWzHP nbca+xjsi49zQFvDd0H2LPWN4Vt3DsucXwMjq7inZw75gLcz708/EHd0qXZDcRzfSxZ0 7kDs49n1PRUiQq+9cl758bS/aAICWeyAN6lZMO3aIEDR13IGNplCjXw1XxGPk3ye2Zkd fH8NAHgzcFjvvvn34QKYAlHHh8TUYCSMJrRJRYZ7My+EGnZPs4pJaymVO3CoGq2/cWyG 8OIw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:in-reply-to:content-disposition :mime-version:references:message-id:subject:cc:to:from:date; bh=wVbNep79eQDUVIgfOZANfp9QUC3JRe9+O7ub2seb3jc=; b=eZnyPGRDLFE33cQ5g/wlURVXnnIhYMGGhm8OzPrRzkS/6qca59x7Excy6QIz81ehL8 CC6+u9/m73x1+VhbscA24Xb2HP1c9ock08NF40XjxaEcatKlOwiZtk2b2Wsq/pO5YlmG kdyIGNfnkcv7bQXSE3QF08vX74zPU8flyo+AfgaoctCu7vH5t9okP/Kp9SvbWU/ZBIRb zUWRQNeOGCeooVmhDadN/bD9uBC0l2g0XN61gt0NM3EAfYrqegNBZiL3jp6vJgYgnWRx yy5ivWddWswQrym5WWDfmMCHCVxlw2zPr0zIGXAynslLiUPLLvmHaQyswcdfBRWSKNx4 P++w== ARC-Authentication-Results: i=1; mx.google.com; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id q21si2987123edg.71.2020.08.22.02.53.56; Sat, 22 Aug 2020 02:54:20 -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; 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 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727055AbgHVJis (ORCPT + 99 others); Sat, 22 Aug 2020 05:38:48 -0400 Received: from asavdk4.altibox.net ([109.247.116.15]:54562 "EHLO asavdk4.altibox.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725864AbgHVJir (ORCPT ); Sat, 22 Aug 2020 05:38:47 -0400 Received: from ravnborg.org (unknown [188.228.123.71]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by asavdk4.altibox.net (Postfix) with ESMTPS id 24DA880516; Sat, 22 Aug 2020 11:38:42 +0200 (CEST) Date: Sat, 22 Aug 2020 11:38:40 +0200 From: Sam Ravnborg To: Enric Balletbo i Serra Cc: linux-kernel@vger.kernel.org, Jernej Skrabec , drinkcat@chromium.org, Jonas Karlman , David Airlie , Neil Armstrong , dri-devel@lists.freedesktop.org, Andrzej Hajda , Laurent Pinchart , hsinyi@chromium.org, matthias.bgg@gmail.com, Collabora Kernel ML Subject: Re: [PATCH 3/3] drm/bridge: ps8640: Rework power state handling Message-ID: <20200822093840.GC430436@ravnborg.org> References: <20200615205320.790334-1-enric.balletbo@collabora.com> <20200615205320.790334-4-enric.balletbo@collabora.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20200615205320.790334-4-enric.balletbo@collabora.com> X-CMAE-Score: 0 X-CMAE-Analysis: v=2.3 cv=aP3eV41m c=1 sm=1 tr=0 a=S6zTFyMACwkrwXSdXUNehg==:117 a=S6zTFyMACwkrwXSdXUNehg==:17 a=kj9zAlcOel0A:10 a=QX4gbG5DAAAA:8 a=e5mUnYsNAAAA:8 a=gsnspH9XThcp_ju6__IA:9 a=CjuIK1q_8ugA:10 a=AbAUZ8qAyYyZVLSsDulk:22 a=Vxmtnl_E_bksehYqCbjh:22 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Mon, Jun 15, 2020 at 10:53:20PM +0200, Enric Balletbo i Serra wrote: > The get_edid() callback can be triggered anytime by an ioctl, i.e > > drm_mode_getconnector (ioctl) > -> drm_helper_probe_single_connector_modes > -> drm_bridge_connector_get_modes > -> ps8640_bridge_get_edid > > Actually if the bridge pre_enable() function was not called before > get_edid(), the driver will not be able to get the EDID properly and > display will not work until a second get_edid() call is issued and if > pre_enable() is called before. The side effect of this, for example, is > that you see anything when `Frecon` starts, neither the splash screen, > until the graphical session manager starts. > > To fix this we need to make sure that all we need is enabled before > reading the EDID. This means the following: > > 1. If get_edid() is called before having the device powered we need to > power on the device. In such case, the driver will power off again the > device. > > 2. If get_edid() is called after having the device powered, all should > just work. We added a powered flag in order to avoid recurrent calls > to ps8640_bridge_poweron() and unneeded delays. > > 3. This seems to be specific for this device, but we need to make sure > the panel is powered on before do a power on cycle on this device. > Otherwise the device fails to retrieve the EDID. > > Signed-off-by: Enric Balletbo i Serra > --- > > drivers/gpu/drm/bridge/parade-ps8640.c | 79 ++++++++++++++++++++++++-- > 1 file changed, 73 insertions(+), 6 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c > index 9f7b7a9c53c52..ca651480891df 100644 > --- a/drivers/gpu/drm/bridge/parade-ps8640.c > +++ b/drivers/gpu/drm/bridge/parade-ps8640.c > @@ -65,6 +65,7 @@ struct ps8640 { > struct regulator_bulk_data supplies[2]; > struct gpio_desc *gpio_reset; > struct gpio_desc *gpio_powerdown; > + bool powered; > }; > > static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e) > @@ -91,13 +92,25 @@ static int ps8640_bridge_vdo_control(struct ps8640 *ps_bridge, > return 0; > } > > -static void ps8640_pre_enable(struct drm_bridge *bridge) > +static void ps8640_bridge_poweron(struct ps8640 *ps_bridge) > { > - struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); > struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL]; > + struct drm_bridge *panel; > unsigned long timeout; > int ret, status; > > + if (ps_bridge->powered) > + return; > + > + /* > + * That seems to be specific to this chip, and a weird behaviour, but > + * we need to call drm_panel_prepare before issuing a poweron cycle. If > + * we don't do this, the chip is not able to read properly the EDID. > + */ > + panel = ps_bridge->panel_bridge; > + if (panel->funcs && panel->funcs->pre_enable) > + panel->funcs->pre_enable(panel); > + > ret = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies), > ps_bridge->supplies); > if (ret < 0) { > @@ -164,6 +177,8 @@ static void ps8640_pre_enable(struct drm_bridge *bridge) > goto err_regulators_disable; > } > > + ps_bridge->powered = true; > + > return; > > err_regulators_disable: > @@ -171,12 +186,13 @@ static void ps8640_pre_enable(struct drm_bridge *bridge) > ps_bridge->supplies); > } > > -static void ps8640_post_disable(struct drm_bridge *bridge) > +static void ps8640_bridge_poweroff(struct ps8640 *ps_bridge) > { > - struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); > + struct drm_bridge *panel; > int ret; > > - ps8640_bridge_vdo_control(ps_bridge, DISABLE); > + if (!ps_bridge->powered) > + return; > > gpiod_set_value(ps_bridge->gpio_reset, 1); > gpiod_set_value(ps_bridge->gpio_powerdown, 1); > @@ -184,6 +200,32 @@ static void ps8640_post_disable(struct drm_bridge *bridge) > ps_bridge->supplies); > if (ret < 0) > DRM_ERROR("cannot disable regulators %d\n", ret); > + > + panel = ps_bridge->panel_bridge; > + if (panel->funcs && panel->funcs->post_disable) > + panel->funcs->post_disable(panel); > + > + ps_bridge->powered = false; > +} > + > +static void ps8640_pre_enable(struct drm_bridge *bridge) > +{ > + struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); > + int ret; > + > + ps8640_bridge_poweron(ps_bridge); > + > + ret = ps8640_bridge_vdo_control(ps_bridge, DISABLE); > + if (ret < 0) > + ps8640_bridge_poweroff(ps_bridge); > +} > + > +static void ps8640_post_disable(struct drm_bridge *bridge) > +{ > + struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); > + > + ps8640_bridge_vdo_control(ps_bridge, DISABLE); > + ps8640_bridge_poweroff(ps_bridge); > } Hi Enric. Would is be possible to use drm_bridge_chain_pre_enable() and drm_bridge_chain_post_disable() rather than hardcoding the dependencies here. The the already present logic to handle a bridged chain is used when pre_enable and post_disable. Seems better to use the present logic to handle bridged chains if possible. And it should simplify this logic a bit too. Sam > > static int ps8640_bridge_attach(struct drm_bridge *bridge, > @@ -249,9 +291,34 @@ 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; > + struct edid *edid; > + > + /* > + * When we end calling get_edid() triggered by an ioctl, i.e > + * > + * drm_mode_getconnector (ioctl) > + * -> drm_helper_probe_single_connector_modes > + * -> drm_bridge_connector_get_modes > + * -> ps8640_bridge_get_edid > + * > + * We need to make sure that what we need is enabled before reading > + * EDID, for this chip, we need to do a full poweron, otherwise it will > + * fail. > + */ > + ps8640_bridge_poweron(ps_bridge); > > - return drm_get_edid(connector, > + edid = drm_get_edid(connector, > ps_bridge->page[PAGE0_DP_CNTL]->adapter); > + > + /* > + * If we call the get_edid() function without having enabled the chip > + * before, return the chip to its original power state. > + */ > + if (poweroff) > + ps8640_bridge_poweroff(ps_bridge); > + > + return edid; > } > > static const struct drm_bridge_funcs ps8640_bridge_funcs = { > -- > 2.27.0 > > _______________________________________________ > dri-devel mailing list > dri-devel@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/dri-devel