Received: by 2002:a05:6a10:22f:0:0:0:0 with SMTP id 15csp847278pxk; Mon, 31 Aug 2020 02:49:59 -0700 (PDT) X-Google-Smtp-Source: ABdhPJy8FCz7GksUSz1sZAdfBu32PSm4G4IstM97eiRViNfJaMw1jcYRLIWheL97WnhuG0Mjda/6 X-Received: by 2002:a17:906:840c:: with SMTP id n12mr337874ejx.246.1598867398971; Mon, 31 Aug 2020 02:49:58 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1598867398; cv=none; d=google.com; s=arc-20160816; b=IQqlmTKpu3UN5VfNIFatIsukWwbJ4jjEyVi9gje8Mdm4a5cFrMzAxXxoWClrAEW+RF 1PMkUZnwplvHWJcui/zCyB6j+jXWLlmpv/i4Nz3mypkzJ4xmLwMg4v0C4tZ23zIo7xoL ajdRKKsPOLeBGJ7QiE9qgzXBb0yGNm61pOSglThGZJgong4+oC8JRXgtsW3qktkJlQdJ OVlQQsE1iSfMGXfX8Ir8w8rx8cgz14gDagpHW1/A5R390gBQT5GFvgjjkPdN99NgRVhD 5nB0ViktOXbX4davAelRU1bysQWeDt5Da2KrvOOdN7KtB432KvyzYXbUAaarUtEYKcrZ mvVg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding :content-language:in-reply-to:mime-version:user-agent:date :message-id:from:references:cc:to:subject; bh=3k2AWn8No2cGspWuPJ0RT9UR07HO5mpIxsex8bMzgNg=; b=K81jO0FamXkhuJz5bH5HtauGZSBILC3GDgtwclCsvH5pp0Ox8WHWO9WVwmGkmjn6hG uIQt3JfPdhTR4sFeIWMCBDkKrbYhqOhWH/77vCoI7Ylhv3r7nHhRoIdVyo0/JGBHUJrL /1S1LuscLv7tlFX/yoXxQZSri1Y5keQVlikYm3m8Iu6g6Yo4CStMChwX54WZthlHWzgJ rzD722qqFCzx2JXA1Uswpxr2ig17aTB30wzGr4iB+be58pUPZ+pv5NfgmEINzKgqLRL+ LhGifVDo8Uc0hbxp0QpqDQBmtkLxJsX/2zw1ABSZwOuHFRBc/uIaAaszuZRb5TYO24Aw wMMw== 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=collabora.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id x18si5369980ejd.265.2020.08.31.02.49.35; Mon, 31 Aug 2020 02:49:58 -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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=collabora.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726775AbgHaJpz (ORCPT + 99 others); Mon, 31 Aug 2020 05:45:55 -0400 Received: from bhuna.collabora.co.uk ([46.235.227.227]:38020 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726042AbgHaJpy (ORCPT ); Mon, 31 Aug 2020 05:45:54 -0400 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: eballetbo) with ESMTPSA id A5267291F0E Subject: Re: [PATCH v3 1/1] drm/bridge: ps8640: Rework power state handling To: Bilal Wasim Cc: linux-kernel@vger.kernel.org, Collabora Kernel ML , matthias.bgg@gmail.com, drinkcat@chromium.org, hsinyi@chromium.org, laurent.pinchart@ideasonboard.com, sam@ravnborg.org, Andrzej Hajda , Daniel Vetter , David Airlie , Jernej Skrabec , Jonas Karlman , Neil Armstrong , dri-devel@lists.freedesktop.org References: <20200827085911.944899-1-enric.balletbo@collabora.com> <20200827085911.944899-2-enric.balletbo@collabora.com> <20200831143223.1a775ba6@a-VirtualBox> From: Enric Balletbo i Serra Message-ID: Date: Mon, 31 Aug 2020 11:45:47 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.11.0 MIME-Version: 1.0 In-Reply-To: <20200831143223.1a775ba6@a-VirtualBox> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Bilal, On 31/8/20 11:32, Bilal Wasim wrote: > > Hi Enric, > > On Thu, 27 Aug 2020 10:59:11 +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 >> --- >> >> Changes in v3: >> - Make poweron/poweroff and pre_enable/post_disable reverse one to >> each other (Sam Ravnborg) >> >> Changes in v2: >> - Use drm_bridge_chain_pre_enable/post_disable() helpers (Sam >> Ravnborg) >> >> drivers/gpu/drm/bridge/parade-ps8640.c | 68 >> ++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 10 >> deletions(-) >> >> diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c >> b/drivers/gpu/drm/bridge/parade-ps8640.c index >> 9f7b7a9c53c5..7bd0affa057a 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,15 @@ 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]; >> unsigned long timeout; >> int ret, status; >> >> + if (ps_bridge->powered) >> + return; >> + >> ret = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies), >> ps_bridge->supplies); >> if (ret < 0) { >> @@ -152,10 +155,6 @@ static void ps8640_pre_enable(struct drm_bridge >> *bridge) goto err_regulators_disable; >> } >> >> - ret = ps8640_bridge_vdo_control(ps_bridge, ENABLE); >> - if (ret) >> - goto err_regulators_disable; >> - >> /* Switch access edp panel's edid through i2c */ >> ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS, >> I2C_BYPASS_EN); >> @@ -164,6 +163,8 @@ static void ps8640_pre_enable(struct drm_bridge >> *bridge) goto err_regulators_disable; >> } >> >> + ps_bridge->powered = true; >> + >> return; >> >> err_regulators_disable: >> @@ -171,12 +172,12 @@ 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); >> 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 +185,28 @@ static void ps8640_post_disable(struct >> drm_bridge *bridge) ps_bridge->supplies); >> if (ret < 0) >> DRM_ERROR("cannot disable regulators %d\n", ret); >> + >> + 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, ENABLE); >> + 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); >> } >> >> static int ps8640_bridge_attach(struct drm_bridge *bridge, >> @@ -249,9 +272,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. >> + */ >> + drm_bridge_chain_pre_enable(bridge); > > Are we sure that pre_enable is always good enough to get the EDID? I > know that we only have support for ps8640 on the MT8173 SoC which works > only with pre_enable, but I think a more scalable solution would be to > call drm_bridge_chain_pre_enable / drm_bridge_chain_enable here, and > drm_bridge_chain_post_disable / drm_bridge_chain_disable when disabling > the chain. If this is not a concern and we are sure that pre_enable > will always work (especially on newer boards), then please ignore my > comment. > Not a drm_bridge API expert, and sometimes I am confused about it, but, from what I know, I'm pretty sure that we _don't_ want to call drm_bridge_chain_enable(). The call drm_bridge_chain_pre_enable() will end with calling drm_panel_prepare(), which, as per documentation: * Calling this function will enable power and deassert any reset signals to * the panel. After this has completed it is possible to communicate with any * integrated circuitry via a command bus. Calling drm_bridge_chain_enable() too will end calling drm_panel_enable(), and, as per documentation: * Calling this function will cause the panel display drivers to be turned on * and the backlight to be enabled. Content will be visible on screen after * this call completes Which can trigger a screen flickering and enable more things that what we want. Reading the EDID should be possible just after a call of drm_bridge_prepare(). Enable the panel should not be required. Cheers, Enric > Other than this, everything looks fine. > >> >> - 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) >> + drm_bridge_chain_post_disable(bridge); >> + >> + return edid; >> } >> >> static const struct drm_bridge_funcs ps8640_bridge_funcs = { > > -Bilal >