All of lore.kernel.org
 help / color / mirror / Atom feed
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
To: Sam Ravnborg <sam@ravnborg.org>
Cc: Neil Armstrong <narmstrong@baylibre.com>,
	David Airlie <airlied@linux.ie>,
	dri-devel@lists.freedesktop.org,
	Thierry Reding <thierry.reding@gmail.com>,
	Marek Vasut <marex@denx.de>,
	Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>,
	Vincent Abriou <vincent.abriou@st.com>,
	Krzysztof Kozlowski <krzk@kernel.org>,
	Jonathan Hunter <jonathanh@nvidia.com>,
	Maxime Ripard <maxime.ripard@bootlin.com>,
	Kukjin Kim <kgene@kernel.org>,
	linux-arm-kernel@lists.infradead.org,
	NXP Linux Team <linux-imx@nxp.com>,
	Pengutronix Kernel Team <kernel@pengutronix.de>,
	Jonas Karlman <jonas@kwiboo.se>,
	Sascha Hauer <s.hauer@pengutronix.de>,
	Alison Wang <alison.wang@nxp.com>,
	Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>,
	Alexios Zavras <alexios.zavras@intel.com>,
	linux-samsung-soc@vger.kernel.org, linux-tegra@vger.kernel.org,
	Thomas Gleixner <tglx@linutronix.de>, Sean Paul <sean@poorly.run>
Subject: Re: [PATCH v1 14/16] drm/panel: call prepare/enable only once
Date: Mon, 2 Dec 2019 17:22:11 +0200	[thread overview]
Message-ID: <20191202152211.GB18532@pendragon.ideasonboard.com> (raw)
In-Reply-To: <20190805165117.GA23301@ravnborg.org>

Hi Sam,

On Mon, Aug 05, 2019 at 06:51:17PM +0200, Sam Ravnborg wrote:
> > On Sun, Aug 04, 2019 at 10:16:35PM +0200, Sam Ravnborg wrote:
> > > Many panel drivers duplicate logic to prevent prepare to be called
> > > for a panel that is already prepared.
> > > Likewise for enable.
> > > 
> > > Implement this logic in drm_panel so the individual drivers
> > > no longer needs this.
> > > A panel is considered prepared/enabled only if the prepare/enable call
> > > succeeds.
> > > For disable/unprepare it is unconditionally considered
> > > disabled/unprepared.
> > > 
> > > This allows calls to prepare/enable again, even if there were
> > > some issue disabling a regulator or similar during disable/unprepare.
> > 
> > Is this the right place to handle this ? Shouldn't the upper layers
> > ensure than enable/disable and prepare/unprepare are correcty balanced,
> > and not called multiple times ? Adding enabled and prepared state to
> > drm_panel not only doesn't align well with atomic state handling, but
> > also would hide issues in upper layers that should really be fixed
> > there.
> 
> The main rationale behind starting on this was that ~15 panel drivers
> already implements logic to prevent the prepare/enable/disable/unprepare
> functions to be called out of order.
> $ cd drivers/gpu/drm/panel/; git grep enabled | grep bool | wc -l
> 
> Several of the panel drivers also implements a
> mipi_dsi_driver.shutdown() or platform_driver.shutdown().
> To the best of my knowledge we cannot guarantee that the upper layers
> have done the proper disable()/unprepare() dance before a shutdown.

If the display controller drivers all behaved correctly, their
.shutdown() implementation would disable all the output, and thus
disable the panels. I think that's the best way forward, and we should
ideally remove .shutdown() from the panel drivers, as otherwise the
panel may be disabled before the display driver .shutdown() operation is
called, and weird things can then happen.

This being said, guaranteeing proper operation of the display controller
drivers isn't easy, so I'm not calling for removing .shutdown() from
panel drivers right now, but I think we shouldn't accept that operation
in new panel drivers going forward.

> So the flags exists to allow the driver to unconditionally call
> disable() / unprepare() in the shutdown methods.
> Same goes for *_driver.remove()

I'd rather get rid of the hacks instead of trying to refactor them in
generic hack-support helpers ;-) But I get your point, as an interim
measure this is probably our best option.

> One improvement could be to detect if the panel is prepare() when
> upper layers call enable() and warn/error in this situation.
> With the current implementation this is not checked at all.
> Likewise for unprepare() (require it was never enabled or disable() was
> caled first)
> 
> I claim the check exists for the benefit of .remove and .shutdown,
> so we could also check if prepare() or enable() is called twice.
> 
> Adding logic to call prepare() automagically would hide probems in upper
> layers and this was only briefly considered - and discarded as hiding
> bugs.

I agree with you.

> So to sum up:
> - Moving the checks from drivers to the core is a good thing
> - The core shall check that a panel is prepared when enable is called
>   and error out if not (or warn).
> - The core shall check that a panel is disabled when unprepare is called
>   and error out if not (or warn).
>   The core shall check if prepare() and enable() is called out of order.
> 
> The patch needs to be extended to cover the last three points.
> 
> Laurent / Emil / Thierry - agree/comments?

Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Maybe with a note in the Documentation/gpu/todo.rst to remove
.shutdown() in panel drivers as a long term goal ?

> Note: Did a quick round to see if could spot any wrong use of
> drm_panel_* functions.
> Most looked good, but then I did not do a throughly check.
> 
> bridge/analogix/analogix_dp_core.c looks fishy.
> Looks like analogix_dp_prepare_panel() is a nop the way it is called.
> I did not look too much on this, maybe I am wrong.
> 
> > > Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
> > > Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> > > Cc: Maxime Ripard <maxime.ripard@bootlin.com>
> > > Cc: Sean Paul <sean@poorly.run>
> > > Cc: Thierry Reding <thierry.reding@gmail.com>
> > > Cc: Sam Ravnborg <sam@ravnborg.org>
> > > Cc: David Airlie <airlied@linux.ie>
> > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > ---
> > >  drivers/gpu/drm/drm_panel.c | 66 ++++++++++++++++++++++++++++++-------
> > >  include/drm/drm_panel.h     | 21 ++++++++++++
> > >  2 files changed, 75 insertions(+), 12 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
> > > index da19d5b4a2f4..0853764040de 100644
> > > --- a/drivers/gpu/drm/drm_panel.c
> > > +++ b/drivers/gpu/drm/drm_panel.c
> > > @@ -66,10 +66,21 @@ EXPORT_SYMBOL(drm_panel_init);
> > >   */
> > >  int drm_panel_prepare(struct drm_panel *panel)
> > >  {
> > > -	if (panel && panel->funcs && panel->funcs->prepare)
> > > -		return panel->funcs->prepare(panel);
> > > +	int ret = -ENOSYS;
> > >  
> > > -	return panel ? -ENOSYS : -EINVAL;
> > > +	if (!panel)
> > > +		return -EINVAL;
> > > +
> > > +	if (panel->prepared)
> > > +		return 0;
> > > +
> > > +	if (panel->funcs && panel->funcs->prepare)
> > > +		ret = panel->funcs->prepare(panel);
> > > +
> > > +	if (ret >= 0)
> > > +		panel->prepared = true;
> > > +
> > > +	return ret;
> > >  }
> > >  EXPORT_SYMBOL(drm_panel_prepare);
> > >  
> > > @@ -85,10 +96,21 @@ EXPORT_SYMBOL(drm_panel_prepare);
> > >   */
> > >  int drm_panel_enable(struct drm_panel *panel)
> > >  {
> > > -	if (panel && panel->funcs && panel->funcs->enable)
> > > -		return panel->funcs->enable(panel);
> > > +	int ret = -ENOSYS;
> > >  
> > > -	return panel ? -ENOSYS : -EINVAL;
> > > +	if (!panel)
> > > +		return -EINVAL;
> > > +
> > > +	if (panel->enabled)
> > > +		return 0;
> > > +
> > > +	if (panel->funcs && panel->funcs->enable)
> > > +		ret = panel->funcs->enable(panel);
> > > +
> > > +	if (ret >= 0)
> > > +		panel->enabled = true;
> > > +
> > > +	return ret;
> > >  }
> > >  EXPORT_SYMBOL(drm_panel_enable);
> > >  
> > > @@ -104,10 +126,20 @@ EXPORT_SYMBOL(drm_panel_enable);
> > >   */
> > >  int drm_panel_disable(struct drm_panel *panel)
> > >  {
> > > -	if (panel && panel->funcs && panel->funcs->disable)
> > > -		return panel->funcs->disable(panel);
> > > +	int ret = -ENOSYS;
> > >  
> > > -	return panel ? -ENOSYS : -EINVAL;
> > > +	if (!panel)
> > > +		return -EINVAL;
> > > +
> > > +	if (!panel->enabled)
> > > +		return 0;
> > > +
> > > +	if (panel->funcs && panel->funcs->disable)
> > > +		ret = panel->funcs->disable(panel);
> > > +
> > > +	panel->enabled = false;
> > > +
> > > +	return ret;
> > >  }
> > >  EXPORT_SYMBOL(drm_panel_disable);
> > >  
> > > @@ -124,10 +156,20 @@ EXPORT_SYMBOL(drm_panel_disable);
> > >   */
> > >  int drm_panel_unprepare(struct drm_panel *panel)
> > >  {
> > > -	if (panel && panel->funcs && panel->funcs->unprepare)
> > > -		return panel->funcs->unprepare(panel);
> > > +	int ret = -ENOSYS;
> > >  
> > > -	return panel ? -ENOSYS : -EINVAL;
> > > +	if (!panel)
> > > +		return -EINVAL;
> > > +
> > > +	if (!panel->prepared)
> > > +		return 0;
> > > +
> > > +	if (panel->funcs && panel->funcs->unprepare)
> > > +		ret = panel->funcs->unprepare(panel);
> > > +
> > > +	panel->prepared = false;
> > > +
> > > +	return ret;
> > >  }
> > >  EXPORT_SYMBOL(drm_panel_unprepare);
> > >  
> > > diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
> > > index 624bd15ecfab..7493500fc9bd 100644
> > > --- a/include/drm/drm_panel.h
> > > +++ b/include/drm/drm_panel.h
> > > @@ -65,6 +65,9 @@ struct drm_panel_funcs {
> > >  	 * @prepare:
> > >  	 *
> > >  	 * Turn on panel and perform set up.
> > > +	 * When the panel is successfully prepared the prepare() function
> > > +	 * will not be called again until the panel has been unprepared.
> > > +	 *
> > >  	 */
> > >  	int (*prepare)(struct drm_panel *panel);
> > >  
> > > @@ -72,6 +75,8 @@ struct drm_panel_funcs {
> > >  	 * @enable:
> > >  	 *
> > >  	 * Enable panel (turn on back light, etc.).
> > > +	 * When the panel is successfully enabled the enable() function
> > > +	 * will not be called again until the panel has been disabled.
> > >  	 */
> > >  	int (*enable)(struct drm_panel *panel);
> > >  
> > > @@ -79,6 +84,7 @@ struct drm_panel_funcs {
> > >  	 * @disable:
> > >  	 *
> > >  	 * Disable panel (turn off back light, etc.).
> > > +	 * If the panel is already disabled the disable() function is not called.
> > >  	 */
> > >  	int (*disable)(struct drm_panel *panel);
> > >  
> > > @@ -86,6 +92,7 @@ struct drm_panel_funcs {
> > >  	 * @unprepare:
> > >  	 *
> > >  	 * Turn off panel.
> > > +	 * If the panel is already unprepared the unprepare() function is not called.
> > >  	 */
> > >  	int (*unprepare)(struct drm_panel *panel);
> > >  
> > > @@ -145,6 +152,20 @@ struct drm_panel {
> > >  	 * Panel entry in registry.
> > >  	 */
> > >  	struct list_head list;
> > > +
> > > +	/**
> > > +	 * @prepared:
> > > +	 *
> > > +	 * Set to true when the panel is successfully prepared.
> > > +	 */
> > > +	bool prepared;
> > > +
> > > +	/**
> > > +	 * @enabled:
> > > +	 *
> > > +	 * Set to true when the panel is successfully enabled.
> > > +	 */
> > > +	bool enabled;
> > >  };
> > >  
> > >  void drm_panel_init(struct drm_panel *panel);

-- 
Regards,

Laurent Pinchart
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

WARNING: multiple messages have this Message-ID (diff)
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
To: Sam Ravnborg <sam@ravnborg.org>
Cc: dri-devel@lists.freedesktop.org,
	Thierry Reding <thierry.reding@gmail.com>,
	Alexios Zavras <alexios.zavras@intel.com>,
	Alison Wang <alison.wang@nxp.com>,
	Allison Randal <allison@lohutok.net>,
	Andrzej Hajda <a.hajda@samsung.com>,
	Benjamin Gaignard <benjamin.gaignard@linaro.org>,
	Daniel Vetter <daniel@ffwll.ch>, David Airlie <airlied@linux.ie>,
	Enrico Weigelt <info@metux.net>,
	Fabio Estevam <festevam@gmail.com>,
	Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>,
	Inki Dae <inki.dae@samsung.com>,
	Jernej Skrabec <jernej.skrabec@siol.net>,
	Jonas Karlman <jonas@kwiboo.se>,
	Jonathan Hunter <jonathanh@nvidia.com>,
	Joonyoung Shim <jy0922.shim@samsung.com>,
	Krzysztof Kozlowski <krzk@kernel.org>,
	Kukjin Kim <kgene@kernel.org>,
	Kyungmin Park <kyungmin.park@samsung.com>,
	Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>,
	Linus Walleij <linus.walleij@linaro.org>,
	linux-arm-kernel@lists.infradead.org,
	linux-samsung-soc@vger.kernel.org, linux-tegra@vger.kernel.org,
	Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
	Marek Vasut <marex@denx.de>,
	Maxime Ripard <maxime.ripard@bootlin.com>,
	Neil Armstrong <narmstrong@baylibre.com>,
	NXP Linux Team <linux-imx@nxp.com>,
	Pengutronix Kernel Team <kernel@pengutronix.de>,
	Philipp Zabel <p.zabel@pengutronix.de>,
	Sascha Hauer <s.hauer@pengutronix.de>,
	Sean Paul <sean@poorly.run>,
	Seung-Woo Kim <sw0312.kim@samsung.com>,
	Shawn Guo <shawnguo@kernel.org>, Stefan Agner <stefan@agner.ch>,
	Thomas Gleixner <tglx@linutronix.de>,
	Vincent Abriou <vincent.abriou@st.com>
Subject: Re: [PATCH v1 14/16] drm/panel: call prepare/enable only once
Date: Mon, 2 Dec 2019 17:22:11 +0200	[thread overview]
Message-ID: <20191202152211.GB18532@pendragon.ideasonboard.com> (raw)
In-Reply-To: <20190805165117.GA23301@ravnborg.org>

Hi Sam,

On Mon, Aug 05, 2019 at 06:51:17PM +0200, Sam Ravnborg wrote:
> > On Sun, Aug 04, 2019 at 10:16:35PM +0200, Sam Ravnborg wrote:
> > > Many panel drivers duplicate logic to prevent prepare to be called
> > > for a panel that is already prepared.
> > > Likewise for enable.
> > > 
> > > Implement this logic in drm_panel so the individual drivers
> > > no longer needs this.
> > > A panel is considered prepared/enabled only if the prepare/enable call
> > > succeeds.
> > > For disable/unprepare it is unconditionally considered
> > > disabled/unprepared.
> > > 
> > > This allows calls to prepare/enable again, even if there were
> > > some issue disabling a regulator or similar during disable/unprepare.
> > 
> > Is this the right place to handle this ? Shouldn't the upper layers
> > ensure than enable/disable and prepare/unprepare are correcty balanced,
> > and not called multiple times ? Adding enabled and prepared state to
> > drm_panel not only doesn't align well with atomic state handling, but
> > also would hide issues in upper layers that should really be fixed
> > there.
> 
> The main rationale behind starting on this was that ~15 panel drivers
> already implements logic to prevent the prepare/enable/disable/unprepare
> functions to be called out of order.
> $ cd drivers/gpu/drm/panel/; git grep enabled | grep bool | wc -l
> 
> Several of the panel drivers also implements a
> mipi_dsi_driver.shutdown() or platform_driver.shutdown().
> To the best of my knowledge we cannot guarantee that the upper layers
> have done the proper disable()/unprepare() dance before a shutdown.

If the display controller drivers all behaved correctly, their
.shutdown() implementation would disable all the output, and thus
disable the panels. I think that's the best way forward, and we should
ideally remove .shutdown() from the panel drivers, as otherwise the
panel may be disabled before the display driver .shutdown() operation is
called, and weird things can then happen.

This being said, guaranteeing proper operation of the display controller
drivers isn't easy, so I'm not calling for removing .shutdown() from
panel drivers right now, but I think we shouldn't accept that operation
in new panel drivers going forward.

> So the flags exists to allow the driver to unconditionally call
> disable() / unprepare() in the shutdown methods.
> Same goes for *_driver.remove()

I'd rather get rid of the hacks instead of trying to refactor them in
generic hack-support helpers ;-) But I get your point, as an interim
measure this is probably our best option.

> One improvement could be to detect if the panel is prepare() when
> upper layers call enable() and warn/error in this situation.
> With the current implementation this is not checked at all.
> Likewise for unprepare() (require it was never enabled or disable() was
> caled first)
> 
> I claim the check exists for the benefit of .remove and .shutdown,
> so we could also check if prepare() or enable() is called twice.
> 
> Adding logic to call prepare() automagically would hide probems in upper
> layers and this was only briefly considered - and discarded as hiding
> bugs.

I agree with you.

> So to sum up:
> - Moving the checks from drivers to the core is a good thing
> - The core shall check that a panel is prepared when enable is called
>   and error out if not (or warn).
> - The core shall check that a panel is disabled when unprepare is called
>   and error out if not (or warn).
>   The core shall check if prepare() and enable() is called out of order.
> 
> The patch needs to be extended to cover the last three points.
> 
> Laurent / Emil / Thierry - agree/comments?

Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Maybe with a note in the Documentation/gpu/todo.rst to remove
.shutdown() in panel drivers as a long term goal ?

> Note: Did a quick round to see if could spot any wrong use of
> drm_panel_* functions.
> Most looked good, but then I did not do a throughly check.
> 
> bridge/analogix/analogix_dp_core.c looks fishy.
> Looks like analogix_dp_prepare_panel() is a nop the way it is called.
> I did not look too much on this, maybe I am wrong.
> 
> > > Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
> > > Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> > > Cc: Maxime Ripard <maxime.ripard@bootlin.com>
> > > Cc: Sean Paul <sean@poorly.run>
> > > Cc: Thierry Reding <thierry.reding@gmail.com>
> > > Cc: Sam Ravnborg <sam@ravnborg.org>
> > > Cc: David Airlie <airlied@linux.ie>
> > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > ---
> > >  drivers/gpu/drm/drm_panel.c | 66 ++++++++++++++++++++++++++++++-------
> > >  include/drm/drm_panel.h     | 21 ++++++++++++
> > >  2 files changed, 75 insertions(+), 12 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
> > > index da19d5b4a2f4..0853764040de 100644
> > > --- a/drivers/gpu/drm/drm_panel.c
> > > +++ b/drivers/gpu/drm/drm_panel.c
> > > @@ -66,10 +66,21 @@ EXPORT_SYMBOL(drm_panel_init);
> > >   */
> > >  int drm_panel_prepare(struct drm_panel *panel)
> > >  {
> > > -	if (panel && panel->funcs && panel->funcs->prepare)
> > > -		return panel->funcs->prepare(panel);
> > > +	int ret = -ENOSYS;
> > >  
> > > -	return panel ? -ENOSYS : -EINVAL;
> > > +	if (!panel)
> > > +		return -EINVAL;
> > > +
> > > +	if (panel->prepared)
> > > +		return 0;
> > > +
> > > +	if (panel->funcs && panel->funcs->prepare)
> > > +		ret = panel->funcs->prepare(panel);
> > > +
> > > +	if (ret >= 0)
> > > +		panel->prepared = true;
> > > +
> > > +	return ret;
> > >  }
> > >  EXPORT_SYMBOL(drm_panel_prepare);
> > >  
> > > @@ -85,10 +96,21 @@ EXPORT_SYMBOL(drm_panel_prepare);
> > >   */
> > >  int drm_panel_enable(struct drm_panel *panel)
> > >  {
> > > -	if (panel && panel->funcs && panel->funcs->enable)
> > > -		return panel->funcs->enable(panel);
> > > +	int ret = -ENOSYS;
> > >  
> > > -	return panel ? -ENOSYS : -EINVAL;
> > > +	if (!panel)
> > > +		return -EINVAL;
> > > +
> > > +	if (panel->enabled)
> > > +		return 0;
> > > +
> > > +	if (panel->funcs && panel->funcs->enable)
> > > +		ret = panel->funcs->enable(panel);
> > > +
> > > +	if (ret >= 0)
> > > +		panel->enabled = true;
> > > +
> > > +	return ret;
> > >  }
> > >  EXPORT_SYMBOL(drm_panel_enable);
> > >  
> > > @@ -104,10 +126,20 @@ EXPORT_SYMBOL(drm_panel_enable);
> > >   */
> > >  int drm_panel_disable(struct drm_panel *panel)
> > >  {
> > > -	if (panel && panel->funcs && panel->funcs->disable)
> > > -		return panel->funcs->disable(panel);
> > > +	int ret = -ENOSYS;
> > >  
> > > -	return panel ? -ENOSYS : -EINVAL;
> > > +	if (!panel)
> > > +		return -EINVAL;
> > > +
> > > +	if (!panel->enabled)
> > > +		return 0;
> > > +
> > > +	if (panel->funcs && panel->funcs->disable)
> > > +		ret = panel->funcs->disable(panel);
> > > +
> > > +	panel->enabled = false;
> > > +
> > > +	return ret;
> > >  }
> > >  EXPORT_SYMBOL(drm_panel_disable);
> > >  
> > > @@ -124,10 +156,20 @@ EXPORT_SYMBOL(drm_panel_disable);
> > >   */
> > >  int drm_panel_unprepare(struct drm_panel *panel)
> > >  {
> > > -	if (panel && panel->funcs && panel->funcs->unprepare)
> > > -		return panel->funcs->unprepare(panel);
> > > +	int ret = -ENOSYS;
> > >  
> > > -	return panel ? -ENOSYS : -EINVAL;
> > > +	if (!panel)
> > > +		return -EINVAL;
> > > +
> > > +	if (!panel->prepared)
> > > +		return 0;
> > > +
> > > +	if (panel->funcs && panel->funcs->unprepare)
> > > +		ret = panel->funcs->unprepare(panel);
> > > +
> > > +	panel->prepared = false;
> > > +
> > > +	return ret;
> > >  }
> > >  EXPORT_SYMBOL(drm_panel_unprepare);
> > >  
> > > diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
> > > index 624bd15ecfab..7493500fc9bd 100644
> > > --- a/include/drm/drm_panel.h
> > > +++ b/include/drm/drm_panel.h
> > > @@ -65,6 +65,9 @@ struct drm_panel_funcs {
> > >  	 * @prepare:
> > >  	 *
> > >  	 * Turn on panel and perform set up.
> > > +	 * When the panel is successfully prepared the prepare() function
> > > +	 * will not be called again until the panel has been unprepared.
> > > +	 *
> > >  	 */
> > >  	int (*prepare)(struct drm_panel *panel);
> > >  
> > > @@ -72,6 +75,8 @@ struct drm_panel_funcs {
> > >  	 * @enable:
> > >  	 *
> > >  	 * Enable panel (turn on back light, etc.).
> > > +	 * When the panel is successfully enabled the enable() function
> > > +	 * will not be called again until the panel has been disabled.
> > >  	 */
> > >  	int (*enable)(struct drm_panel *panel);
> > >  
> > > @@ -79,6 +84,7 @@ struct drm_panel_funcs {
> > >  	 * @disable:
> > >  	 *
> > >  	 * Disable panel (turn off back light, etc.).
> > > +	 * If the panel is already disabled the disable() function is not called.
> > >  	 */
> > >  	int (*disable)(struct drm_panel *panel);
> > >  
> > > @@ -86,6 +92,7 @@ struct drm_panel_funcs {
> > >  	 * @unprepare:
> > >  	 *
> > >  	 * Turn off panel.
> > > +	 * If the panel is already unprepared the unprepare() function is not called.
> > >  	 */
> > >  	int (*unprepare)(struct drm_panel *panel);
> > >  
> > > @@ -145,6 +152,20 @@ struct drm_panel {
> > >  	 * Panel entry in registry.
> > >  	 */
> > >  	struct list_head list;
> > > +
> > > +	/**
> > > +	 * @prepared:
> > > +	 *
> > > +	 * Set to true when the panel is successfully prepared.
> > > +	 */
> > > +	bool prepared;
> > > +
> > > +	/**
> > > +	 * @enabled:
> > > +	 *
> > > +	 * Set to true when the panel is successfully enabled.
> > > +	 */
> > > +	bool enabled;
> > >  };
> > >  
> > >  void drm_panel_init(struct drm_panel *panel);

-- 
Regards,

Laurent Pinchart

WARNING: multiple messages have this Message-ID (diff)
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
To: Sam Ravnborg <sam@ravnborg.org>
Cc: Neil Armstrong <narmstrong@baylibre.com>,
	David Airlie <airlied@linux.ie>,
	Linus Walleij <linus.walleij@linaro.org>,
	dri-devel@lists.freedesktop.org,
	Andrzej Hajda <a.hajda@samsung.com>,
	Thierry Reding <thierry.reding@gmail.com>,
	Benjamin Gaignard <benjamin.gaignard@linaro.org>,
	Fabio Estevam <festevam@gmail.com>, Marek Vasut <marex@denx.de>,
	Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>,
	Joonyoung Shim <jy0922.shim@samsung.com>,
	Vincent Abriou <vincent.abriou@st.com>,
	Krzysztof Kozlowski <krzk@kernel.org>,
	Jonathan Hunter <jonathanh@nvidia.com>,
	Maxime Ripard <maxime.ripard@bootlin.com>,
	Kukjin Kim <kgene@kernel.org>,
	linux-arm-kernel@lists.infradead.org,
	Philipp Zabel <p.zabel@pengutronix.de>,
	NXP Linux Team <linux-imx@nxp.com>,
	Pengutronix Kernel Team <kernel@pengutronix.de>,
	Jonas Karlman <jonas@kwiboo.se>,
	Sascha Hauer <s.hauer@pengutronix.de>,
	Alison Wang <alison.wang@nxp.com>,
	Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
	Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>,
	Inki Dae <inki.dae@samsung.com>,
	Alexios Zavras <alexios.zavras@intel.com>,
	linux-samsung-soc@vger.kernel.org, Stefan Agner <stefan@agner.ch>,
	linux-tegra@vger.kernel.org, Thomas Gleixner <tglx@linutronix.de>,
	Sean Paul <sean@poorly.run>, Allison Randal <allison@lohutok.net>,
	Jernej Skrabec <jernej.skrabec@siol.net>,
	Shawn Guo <shawnguo@kernel.org>,
	Seung-Woo Kim <sw0312.kim@samsung.com>,
	Kyungmin Park <kyungmin.park@samsung.com>,
	Daniel Vetter <daniel@ffwll.ch>, Enrico Weigelt <info@metux.net>
Subject: Re: [PATCH v1 14/16] drm/panel: call prepare/enable only once
Date: Mon, 2 Dec 2019 17:22:11 +0200	[thread overview]
Message-ID: <20191202152211.GB18532@pendragon.ideasonboard.com> (raw)
In-Reply-To: <20190805165117.GA23301@ravnborg.org>

Hi Sam,

On Mon, Aug 05, 2019 at 06:51:17PM +0200, Sam Ravnborg wrote:
> > On Sun, Aug 04, 2019 at 10:16:35PM +0200, Sam Ravnborg wrote:
> > > Many panel drivers duplicate logic to prevent prepare to be called
> > > for a panel that is already prepared.
> > > Likewise for enable.
> > > 
> > > Implement this logic in drm_panel so the individual drivers
> > > no longer needs this.
> > > A panel is considered prepared/enabled only if the prepare/enable call
> > > succeeds.
> > > For disable/unprepare it is unconditionally considered
> > > disabled/unprepared.
> > > 
> > > This allows calls to prepare/enable again, even if there were
> > > some issue disabling a regulator or similar during disable/unprepare.
> > 
> > Is this the right place to handle this ? Shouldn't the upper layers
> > ensure than enable/disable and prepare/unprepare are correcty balanced,
> > and not called multiple times ? Adding enabled and prepared state to
> > drm_panel not only doesn't align well with atomic state handling, but
> > also would hide issues in upper layers that should really be fixed
> > there.
> 
> The main rationale behind starting on this was that ~15 panel drivers
> already implements logic to prevent the prepare/enable/disable/unprepare
> functions to be called out of order.
> $ cd drivers/gpu/drm/panel/; git grep enabled | grep bool | wc -l
> 
> Several of the panel drivers also implements a
> mipi_dsi_driver.shutdown() or platform_driver.shutdown().
> To the best of my knowledge we cannot guarantee that the upper layers
> have done the proper disable()/unprepare() dance before a shutdown.

If the display controller drivers all behaved correctly, their
.shutdown() implementation would disable all the output, and thus
disable the panels. I think that's the best way forward, and we should
ideally remove .shutdown() from the panel drivers, as otherwise the
panel may be disabled before the display driver .shutdown() operation is
called, and weird things can then happen.

This being said, guaranteeing proper operation of the display controller
drivers isn't easy, so I'm not calling for removing .shutdown() from
panel drivers right now, but I think we shouldn't accept that operation
in new panel drivers going forward.

> So the flags exists to allow the driver to unconditionally call
> disable() / unprepare() in the shutdown methods.
> Same goes for *_driver.remove()

I'd rather get rid of the hacks instead of trying to refactor them in
generic hack-support helpers ;-) But I get your point, as an interim
measure this is probably our best option.

> One improvement could be to detect if the panel is prepare() when
> upper layers call enable() and warn/error in this situation.
> With the current implementation this is not checked at all.
> Likewise for unprepare() (require it was never enabled or disable() was
> caled first)
> 
> I claim the check exists for the benefit of .remove and .shutdown,
> so we could also check if prepare() or enable() is called twice.
> 
> Adding logic to call prepare() automagically would hide probems in upper
> layers and this was only briefly considered - and discarded as hiding
> bugs.

I agree with you.

> So to sum up:
> - Moving the checks from drivers to the core is a good thing
> - The core shall check that a panel is prepared when enable is called
>   and error out if not (or warn).
> - The core shall check that a panel is disabled when unprepare is called
>   and error out if not (or warn).
>   The core shall check if prepare() and enable() is called out of order.
> 
> The patch needs to be extended to cover the last three points.
> 
> Laurent / Emil / Thierry - agree/comments?

Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Maybe with a note in the Documentation/gpu/todo.rst to remove
.shutdown() in panel drivers as a long term goal ?

> Note: Did a quick round to see if could spot any wrong use of
> drm_panel_* functions.
> Most looked good, but then I did not do a throughly check.
> 
> bridge/analogix/analogix_dp_core.c looks fishy.
> Looks like analogix_dp_prepare_panel() is a nop the way it is called.
> I did not look too much on this, maybe I am wrong.
> 
> > > Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
> > > Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> > > Cc: Maxime Ripard <maxime.ripard@bootlin.com>
> > > Cc: Sean Paul <sean@poorly.run>
> > > Cc: Thierry Reding <thierry.reding@gmail.com>
> > > Cc: Sam Ravnborg <sam@ravnborg.org>
> > > Cc: David Airlie <airlied@linux.ie>
> > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > ---
> > >  drivers/gpu/drm/drm_panel.c | 66 ++++++++++++++++++++++++++++++-------
> > >  include/drm/drm_panel.h     | 21 ++++++++++++
> > >  2 files changed, 75 insertions(+), 12 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
> > > index da19d5b4a2f4..0853764040de 100644
> > > --- a/drivers/gpu/drm/drm_panel.c
> > > +++ b/drivers/gpu/drm/drm_panel.c
> > > @@ -66,10 +66,21 @@ EXPORT_SYMBOL(drm_panel_init);
> > >   */
> > >  int drm_panel_prepare(struct drm_panel *panel)
> > >  {
> > > -	if (panel && panel->funcs && panel->funcs->prepare)
> > > -		return panel->funcs->prepare(panel);
> > > +	int ret = -ENOSYS;
> > >  
> > > -	return panel ? -ENOSYS : -EINVAL;
> > > +	if (!panel)
> > > +		return -EINVAL;
> > > +
> > > +	if (panel->prepared)
> > > +		return 0;
> > > +
> > > +	if (panel->funcs && panel->funcs->prepare)
> > > +		ret = panel->funcs->prepare(panel);
> > > +
> > > +	if (ret >= 0)
> > > +		panel->prepared = true;
> > > +
> > > +	return ret;
> > >  }
> > >  EXPORT_SYMBOL(drm_panel_prepare);
> > >  
> > > @@ -85,10 +96,21 @@ EXPORT_SYMBOL(drm_panel_prepare);
> > >   */
> > >  int drm_panel_enable(struct drm_panel *panel)
> > >  {
> > > -	if (panel && panel->funcs && panel->funcs->enable)
> > > -		return panel->funcs->enable(panel);
> > > +	int ret = -ENOSYS;
> > >  
> > > -	return panel ? -ENOSYS : -EINVAL;
> > > +	if (!panel)
> > > +		return -EINVAL;
> > > +
> > > +	if (panel->enabled)
> > > +		return 0;
> > > +
> > > +	if (panel->funcs && panel->funcs->enable)
> > > +		ret = panel->funcs->enable(panel);
> > > +
> > > +	if (ret >= 0)
> > > +		panel->enabled = true;
> > > +
> > > +	return ret;
> > >  }
> > >  EXPORT_SYMBOL(drm_panel_enable);
> > >  
> > > @@ -104,10 +126,20 @@ EXPORT_SYMBOL(drm_panel_enable);
> > >   */
> > >  int drm_panel_disable(struct drm_panel *panel)
> > >  {
> > > -	if (panel && panel->funcs && panel->funcs->disable)
> > > -		return panel->funcs->disable(panel);
> > > +	int ret = -ENOSYS;
> > >  
> > > -	return panel ? -ENOSYS : -EINVAL;
> > > +	if (!panel)
> > > +		return -EINVAL;
> > > +
> > > +	if (!panel->enabled)
> > > +		return 0;
> > > +
> > > +	if (panel->funcs && panel->funcs->disable)
> > > +		ret = panel->funcs->disable(panel);
> > > +
> > > +	panel->enabled = false;
> > > +
> > > +	return ret;
> > >  }
> > >  EXPORT_SYMBOL(drm_panel_disable);
> > >  
> > > @@ -124,10 +156,20 @@ EXPORT_SYMBOL(drm_panel_disable);
> > >   */
> > >  int drm_panel_unprepare(struct drm_panel *panel)
> > >  {
> > > -	if (panel && panel->funcs && panel->funcs->unprepare)
> > > -		return panel->funcs->unprepare(panel);
> > > +	int ret = -ENOSYS;
> > >  
> > > -	return panel ? -ENOSYS : -EINVAL;
> > > +	if (!panel)
> > > +		return -EINVAL;
> > > +
> > > +	if (!panel->prepared)
> > > +		return 0;
> > > +
> > > +	if (panel->funcs && panel->funcs->unprepare)
> > > +		ret = panel->funcs->unprepare(panel);
> > > +
> > > +	panel->prepared = false;
> > > +
> > > +	return ret;
> > >  }
> > >  EXPORT_SYMBOL(drm_panel_unprepare);
> > >  
> > > diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
> > > index 624bd15ecfab..7493500fc9bd 100644
> > > --- a/include/drm/drm_panel.h
> > > +++ b/include/drm/drm_panel.h
> > > @@ -65,6 +65,9 @@ struct drm_panel_funcs {
> > >  	 * @prepare:
> > >  	 *
> > >  	 * Turn on panel and perform set up.
> > > +	 * When the panel is successfully prepared the prepare() function
> > > +	 * will not be called again until the panel has been unprepared.
> > > +	 *
> > >  	 */
> > >  	int (*prepare)(struct drm_panel *panel);
> > >  
> > > @@ -72,6 +75,8 @@ struct drm_panel_funcs {
> > >  	 * @enable:
> > >  	 *
> > >  	 * Enable panel (turn on back light, etc.).
> > > +	 * When the panel is successfully enabled the enable() function
> > > +	 * will not be called again until the panel has been disabled.
> > >  	 */
> > >  	int (*enable)(struct drm_panel *panel);
> > >  
> > > @@ -79,6 +84,7 @@ struct drm_panel_funcs {
> > >  	 * @disable:
> > >  	 *
> > >  	 * Disable panel (turn off back light, etc.).
> > > +	 * If the panel is already disabled the disable() function is not called.
> > >  	 */
> > >  	int (*disable)(struct drm_panel *panel);
> > >  
> > > @@ -86,6 +92,7 @@ struct drm_panel_funcs {
> > >  	 * @unprepare:
> > >  	 *
> > >  	 * Turn off panel.
> > > +	 * If the panel is already unprepared the unprepare() function is not called.
> > >  	 */
> > >  	int (*unprepare)(struct drm_panel *panel);
> > >  
> > > @@ -145,6 +152,20 @@ struct drm_panel {
> > >  	 * Panel entry in registry.
> > >  	 */
> > >  	struct list_head list;
> > > +
> > > +	/**
> > > +	 * @prepared:
> > > +	 *
> > > +	 * Set to true when the panel is successfully prepared.
> > > +	 */
> > > +	bool prepared;
> > > +
> > > +	/**
> > > +	 * @enabled:
> > > +	 *
> > > +	 * Set to true when the panel is successfully enabled.
> > > +	 */
> > > +	bool enabled;
> > >  };
> > >  
> > >  void drm_panel_init(struct drm_panel *panel);

-- 
Regards,

Laurent Pinchart

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

WARNING: multiple messages have this Message-ID (diff)
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
To: Sam Ravnborg <sam@ravnborg.org>
Cc: Neil Armstrong <narmstrong@baylibre.com>,
	David Airlie <airlied@linux.ie>,
	dri-devel@lists.freedesktop.org,
	Thierry Reding <thierry.reding@gmail.com>,
	Marek Vasut <marex@denx.de>,
	Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>,
	Vincent Abriou <vincent.abriou@st.com>,
	Krzysztof Kozlowski <krzk@kernel.org>,
	Jonathan Hunter <jonathanh@nvidia.com>,
	Maxime Ripard <maxime.ripard@bootlin.com>,
	Kukjin Kim <kgene@kernel.org>,
	linux-arm-kernel@lists.infradead.org,
	NXP Linux Team <linux-imx@nxp.com>,
	Pengutronix Kernel Team <kernel@pengutronix.de>,
	Jonas Karlman <jonas@kwiboo.se>,
	Sascha Hauer <s.hauer@pengutronix.de>,
	Alison Wang <alison.wang@nxp.com>,
	Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>,
	Alexios Zavras <alexios.zavras@intel.com>,
	linux-samsung-soc@vger.kernel.org, linux-tegra@vger.kernel.org,
	Thomas Gleixner <tglx@linutronix.de>, Sean Paul <sean@poorly.run>,
	Allison Randal <allison@lohutok.net>,
	Jernej Skrabec <jernej.skrabec@siol.net>,
	Shawn Guo <shawnguo@kernel.org>,
	Seung-Woo Kim <sw0312.kim@samsung.com>,
	Kyungmin Park <kyungmin.park@samsung.com>,
	Enrico Weigelt <info@metux.net>
Subject: Re: [PATCH v1 14/16] drm/panel: call prepare/enable only once
Date: Mon, 2 Dec 2019 17:22:11 +0200	[thread overview]
Message-ID: <20191202152211.GB18532@pendragon.ideasonboard.com> (raw)
Message-ID: <20191202152211.mYNIfHsX77pTc5hY5ATe6ib1QAynp8TXzFIiOS9GZVA@z> (raw)
In-Reply-To: <20190805165117.GA23301@ravnborg.org>

Hi Sam,

On Mon, Aug 05, 2019 at 06:51:17PM +0200, Sam Ravnborg wrote:
> > On Sun, Aug 04, 2019 at 10:16:35PM +0200, Sam Ravnborg wrote:
> > > Many panel drivers duplicate logic to prevent prepare to be called
> > > for a panel that is already prepared.
> > > Likewise for enable.
> > > 
> > > Implement this logic in drm_panel so the individual drivers
> > > no longer needs this.
> > > A panel is considered prepared/enabled only if the prepare/enable call
> > > succeeds.
> > > For disable/unprepare it is unconditionally considered
> > > disabled/unprepared.
> > > 
> > > This allows calls to prepare/enable again, even if there were
> > > some issue disabling a regulator or similar during disable/unprepare.
> > 
> > Is this the right place to handle this ? Shouldn't the upper layers
> > ensure than enable/disable and prepare/unprepare are correcty balanced,
> > and not called multiple times ? Adding enabled and prepared state to
> > drm_panel not only doesn't align well with atomic state handling, but
> > also would hide issues in upper layers that should really be fixed
> > there.
> 
> The main rationale behind starting on this was that ~15 panel drivers
> already implements logic to prevent the prepare/enable/disable/unprepare
> functions to be called out of order.
> $ cd drivers/gpu/drm/panel/; git grep enabled | grep bool | wc -l
> 
> Several of the panel drivers also implements a
> mipi_dsi_driver.shutdown() or platform_driver.shutdown().
> To the best of my knowledge we cannot guarantee that the upper layers
> have done the proper disable()/unprepare() dance before a shutdown.

If the display controller drivers all behaved correctly, their
.shutdown() implementation would disable all the output, and thus
disable the panels. I think that's the best way forward, and we should
ideally remove .shutdown() from the panel drivers, as otherwise the
panel may be disabled before the display driver .shutdown() operation is
called, and weird things can then happen.

This being said, guaranteeing proper operation of the display controller
drivers isn't easy, so I'm not calling for removing .shutdown() from
panel drivers right now, but I think we shouldn't accept that operation
in new panel drivers going forward.

> So the flags exists to allow the driver to unconditionally call
> disable() / unprepare() in the shutdown methods.
> Same goes for *_driver.remove()

I'd rather get rid of the hacks instead of trying to refactor them in
generic hack-support helpers ;-) But I get your point, as an interim
measure this is probably our best option.

> One improvement could be to detect if the panel is prepare() when
> upper layers call enable() and warn/error in this situation.
> With the current implementation this is not checked at all.
> Likewise for unprepare() (require it was never enabled or disable() was
> caled first)
> 
> I claim the check exists for the benefit of .remove and .shutdown,
> so we could also check if prepare() or enable() is called twice.
> 
> Adding logic to call prepare() automagically would hide probems in upper
> layers and this was only briefly considered - and discarded as hiding
> bugs.

I agree with you.

> So to sum up:
> - Moving the checks from drivers to the core is a good thing
> - The core shall check that a panel is prepared when enable is called
>   and error out if not (or warn).
> - The core shall check that a panel is disabled when unprepare is called
>   and error out if not (or warn).
>   The core shall check if prepare() and enable() is called out of order.
> 
> The patch needs to be extended to cover the last three points.
> 
> Laurent / Emil / Thierry - agree/comments?

Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Maybe with a note in the Documentation/gpu/todo.rst to remove
.shutdown() in panel drivers as a long term goal ?

> Note: Did a quick round to see if could spot any wrong use of
> drm_panel_* functions.
> Most looked good, but then I did not do a throughly check.
> 
> bridge/analogix/analogix_dp_core.c looks fishy.
> Looks like analogix_dp_prepare_panel() is a nop the way it is called.
> I did not look too much on this, maybe I am wrong.
> 
> > > Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
> > > Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> > > Cc: Maxime Ripard <maxime.ripard@bootlin.com>
> > > Cc: Sean Paul <sean@poorly.run>
> > > Cc: Thierry Reding <thierry.reding@gmail.com>
> > > Cc: Sam Ravnborg <sam@ravnborg.org>
> > > Cc: David Airlie <airlied@linux.ie>
> > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > ---
> > >  drivers/gpu/drm/drm_panel.c | 66 ++++++++++++++++++++++++++++++-------
> > >  include/drm/drm_panel.h     | 21 ++++++++++++
> > >  2 files changed, 75 insertions(+), 12 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
> > > index da19d5b4a2f4..0853764040de 100644
> > > --- a/drivers/gpu/drm/drm_panel.c
> > > +++ b/drivers/gpu/drm/drm_panel.c
> > > @@ -66,10 +66,21 @@ EXPORT_SYMBOL(drm_panel_init);
> > >   */
> > >  int drm_panel_prepare(struct drm_panel *panel)
> > >  {
> > > -	if (panel && panel->funcs && panel->funcs->prepare)
> > > -		return panel->funcs->prepare(panel);
> > > +	int ret = -ENOSYS;
> > >  
> > > -	return panel ? -ENOSYS : -EINVAL;
> > > +	if (!panel)
> > > +		return -EINVAL;
> > > +
> > > +	if (panel->prepared)
> > > +		return 0;
> > > +
> > > +	if (panel->funcs && panel->funcs->prepare)
> > > +		ret = panel->funcs->prepare(panel);
> > > +
> > > +	if (ret >= 0)
> > > +		panel->prepared = true;
> > > +
> > > +	return ret;
> > >  }
> > >  EXPORT_SYMBOL(drm_panel_prepare);
> > >  
> > > @@ -85,10 +96,21 @@ EXPORT_SYMBOL(drm_panel_prepare);
> > >   */
> > >  int drm_panel_enable(struct drm_panel *panel)
> > >  {
> > > -	if (panel && panel->funcs && panel->funcs->enable)
> > > -		return panel->funcs->enable(panel);
> > > +	int ret = -ENOSYS;
> > >  
> > > -	return panel ? -ENOSYS : -EINVAL;
> > > +	if (!panel)
> > > +		return -EINVAL;
> > > +
> > > +	if (panel->enabled)
> > > +		return 0;
> > > +
> > > +	if (panel->funcs && panel->funcs->enable)
> > > +		ret = panel->funcs->enable(panel);
> > > +
> > > +	if (ret >= 0)
> > > +		panel->enabled = true;
> > > +
> > > +	return ret;
> > >  }
> > >  EXPORT_SYMBOL(drm_panel_enable);
> > >  
> > > @@ -104,10 +126,20 @@ EXPORT_SYMBOL(drm_panel_enable);
> > >   */
> > >  int drm_panel_disable(struct drm_panel *panel)
> > >  {
> > > -	if (panel && panel->funcs && panel->funcs->disable)
> > > -		return panel->funcs->disable(panel);
> > > +	int ret = -ENOSYS;
> > >  
> > > -	return panel ? -ENOSYS : -EINVAL;
> > > +	if (!panel)
> > > +		return -EINVAL;
> > > +
> > > +	if (!panel->enabled)
> > > +		return 0;
> > > +
> > > +	if (panel->funcs && panel->funcs->disable)
> > > +		ret = panel->funcs->disable(panel);
> > > +
> > > +	panel->enabled = false;
> > > +
> > > +	return ret;
> > >  }
> > >  EXPORT_SYMBOL(drm_panel_disable);
> > >  
> > > @@ -124,10 +156,20 @@ EXPORT_SYMBOL(drm_panel_disable);
> > >   */
> > >  int drm_panel_unprepare(struct drm_panel *panel)
> > >  {
> > > -	if (panel && panel->funcs && panel->funcs->unprepare)
> > > -		return panel->funcs->unprepare(panel);
> > > +	int ret = -ENOSYS;
> > >  
> > > -	return panel ? -ENOSYS : -EINVAL;
> > > +	if (!panel)
> > > +		return -EINVAL;
> > > +
> > > +	if (!panel->prepared)
> > > +		return 0;
> > > +
> > > +	if (panel->funcs && panel->funcs->unprepare)
> > > +		ret = panel->funcs->unprepare(panel);
> > > +
> > > +	panel->prepared = false;
> > > +
> > > +	return ret;
> > >  }
> > >  EXPORT_SYMBOL(drm_panel_unprepare);
> > >  
> > > diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
> > > index 624bd15ecfab..7493500fc9bd 100644
> > > --- a/include/drm/drm_panel.h
> > > +++ b/include/drm/drm_panel.h
> > > @@ -65,6 +65,9 @@ struct drm_panel_funcs {
> > >  	 * @prepare:
> > >  	 *
> > >  	 * Turn on panel and perform set up.
> > > +	 * When the panel is successfully prepared the prepare() function
> > > +	 * will not be called again until the panel has been unprepared.
> > > +	 *
> > >  	 */
> > >  	int (*prepare)(struct drm_panel *panel);
> > >  
> > > @@ -72,6 +75,8 @@ struct drm_panel_funcs {
> > >  	 * @enable:
> > >  	 *
> > >  	 * Enable panel (turn on back light, etc.).
> > > +	 * When the panel is successfully enabled the enable() function
> > > +	 * will not be called again until the panel has been disabled.
> > >  	 */
> > >  	int (*enable)(struct drm_panel *panel);
> > >  
> > > @@ -79,6 +84,7 @@ struct drm_panel_funcs {
> > >  	 * @disable:
> > >  	 *
> > >  	 * Disable panel (turn off back light, etc.).
> > > +	 * If the panel is already disabled the disable() function is not called.
> > >  	 */
> > >  	int (*disable)(struct drm_panel *panel);
> > >  
> > > @@ -86,6 +92,7 @@ struct drm_panel_funcs {
> > >  	 * @unprepare:
> > >  	 *
> > >  	 * Turn off panel.
> > > +	 * If the panel is already unprepared the unprepare() function is not called.
> > >  	 */
> > >  	int (*unprepare)(struct drm_panel *panel);
> > >  
> > > @@ -145,6 +152,20 @@ struct drm_panel {
> > >  	 * Panel entry in registry.
> > >  	 */
> > >  	struct list_head list;
> > > +
> > > +	/**
> > > +	 * @prepared:
> > > +	 *
> > > +	 * Set to true when the panel is successfully prepared.
> > > +	 */
> > > +	bool prepared;
> > > +
> > > +	/**
> > > +	 * @enabled:
> > > +	 *
> > > +	 * Set to true when the panel is successfully enabled.
> > > +	 */
> > > +	bool enabled;
> > >  };
> > >  
> > >  void drm_panel_init(struct drm_panel *panel);

-- 
Regards,

Laurent Pinchart
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

  reply	other threads:[~2019-12-02 15:22 UTC|newest]

Thread overview: 94+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-08-04 20:16 [PATCH v1 0/16] drm: panel related updates Sam Ravnborg
2019-08-04 20:16 ` Sam Ravnborg
2019-08-04 20:16 ` [PATCH v1 01/16] drm/bridge: tc358767: fix opencoded use of drm_panel_* Sam Ravnborg
2019-08-04 20:16   ` Sam Ravnborg
2019-08-05  9:35   ` Philipp Zabel
2019-08-05  9:35     ` Philipp Zabel
2019-08-05 11:53     ` Sam Ravnborg
2019-08-05 11:53       ` Sam Ravnborg
2019-08-04 20:16 ` [PATCH v1 02/16] drm/exynos: " Sam Ravnborg
2019-08-04 20:16   ` Sam Ravnborg
2019-12-01 11:32   ` Sam Ravnborg
2019-12-01 11:32     ` Sam Ravnborg
2019-12-01 11:32     ` Sam Ravnborg
2019-12-01 11:32     ` Sam Ravnborg
2019-08-04 20:16 ` [PATCH v1 03/16] " Sam Ravnborg
2019-08-04 20:16   ` Sam Ravnborg
2019-12-01 11:32   ` Sam Ravnborg
2019-12-01 11:32     ` Sam Ravnborg
2019-12-01 11:32     ` Sam Ravnborg
2019-12-01 11:32     ` Sam Ravnborg
2019-08-04 20:16 ` [PATCH v1 04/16] drm/imx: " Sam Ravnborg
2019-08-04 20:16   ` Sam Ravnborg
2019-08-05  9:34   ` Philipp Zabel
2019-08-05  9:34     ` Philipp Zabel
2019-08-04 20:16 ` [PATCH v1 05/16] drm/fsl-dcu: " Sam Ravnborg
2019-08-04 20:16   ` Sam Ravnborg
2019-08-05  9:16   ` Stefan Agner
2019-08-05  9:16     ` Stefan Agner
2019-08-05 11:54     ` Sam Ravnborg
2019-08-05 11:54       ` Sam Ravnborg
2019-08-04 20:16 ` [PATCH v1 06/16] drm/msm: " Sam Ravnborg
2019-08-04 20:16   ` Sam Ravnborg
2019-12-01 11:33   ` Sam Ravnborg
2019-12-01 11:33     ` Sam Ravnborg
2019-12-01 11:33     ` Sam Ravnborg
2019-12-01 11:33     ` Sam Ravnborg
2019-08-04 20:16 ` [PATCH v1 07/16] drm/mxsfb: " Sam Ravnborg
2019-08-04 20:16   ` Sam Ravnborg
2019-08-05  9:20   ` Stefan Agner
2019-08-05  9:20     ` Stefan Agner
2019-08-04 20:16 ` [PATCH v1 08/16] drm/sti: " Sam Ravnborg
2019-08-04 20:16   ` Sam Ravnborg
2019-08-07 11:55   ` Benjamin Gaignard
2019-08-07 11:55     ` Benjamin Gaignard
2019-08-04 20:16 ` [PATCH v1 09/16] drm/tegra: " Sam Ravnborg
2019-08-04 20:16   ` Sam Ravnborg
2019-12-01 11:33   ` Sam Ravnborg
2019-12-01 11:33     ` Sam Ravnborg
2019-12-01 11:33     ` Sam Ravnborg
2019-12-01 11:33     ` Sam Ravnborg
2019-08-04 20:16 ` [PATCH v1 10/16] drm/panel: ili9322: move bus_flags to get_modes() Sam Ravnborg
2019-08-04 20:16   ` Sam Ravnborg
2019-08-06 12:56   ` Linus Walleij
2019-08-06 12:56     ` Linus Walleij
2019-08-04 20:16 ` [PATCH v1 11/16] drm/panel: move drm_panel functions to .c file Sam Ravnborg
2019-08-04 20:16   ` Sam Ravnborg
2019-08-05 10:45   ` Laurent Pinchart
2019-08-05 10:45     ` Laurent Pinchart
2019-08-04 20:16 ` [PATCH v1 12/16] drm/panel: use inline comments in drm_panel.h Sam Ravnborg
2019-08-04 20:16   ` Sam Ravnborg
2019-08-05 10:54   ` Laurent Pinchart
2019-08-05 10:54     ` Laurent Pinchart
2019-08-04 20:16 ` [PATCH v1 13/16] drm/panel: drop return code from drm_panel_detach() Sam Ravnborg
2019-08-04 20:16   ` Sam Ravnborg
2019-08-05 10:56   ` Laurent Pinchart
2019-08-05 10:56     ` Laurent Pinchart
2019-08-04 20:16 ` [PATCH v1 14/16] drm/panel: call prepare/enable only once Sam Ravnborg
2019-08-04 20:16   ` Sam Ravnborg
2019-08-05 10:59   ` Laurent Pinchart
2019-08-05 10:59     ` Laurent Pinchart
2019-08-05 13:15     ` Emil Velikov
2019-08-05 13:15       ` Emil Velikov
2019-08-05 16:51     ` Sam Ravnborg
2019-08-05 16:51       ` Sam Ravnborg
2019-12-02 15:22       ` Laurent Pinchart [this message]
2019-12-02 15:22         ` Laurent Pinchart
2019-12-02 15:22         ` Laurent Pinchart
2019-12-02 15:22         ` Laurent Pinchart
2019-08-05 17:01   ` Sean Paul
2019-08-05 17:01     ` Sean Paul
2019-12-02 15:15     ` Laurent Pinchart
2019-12-02 15:15       ` Laurent Pinchart
2019-12-02 15:15       ` Laurent Pinchart
2019-12-02 15:15       ` Laurent Pinchart
2019-08-04 20:16 ` [PATCH v1 15/16] drm/panel: add backlight support Sam Ravnborg
2019-08-04 20:16   ` Sam Ravnborg
2019-08-05 11:04   ` Laurent Pinchart
2019-08-05 11:04     ` Laurent Pinchart
2019-08-04 20:16 ` [PATCH v1 16/16] drm/panel: simple: use drm_panel infrastructure Sam Ravnborg
2019-08-04 20:16   ` Sam Ravnborg
2019-08-05 11:12   ` Laurent Pinchart
2019-08-05 11:12     ` Laurent Pinchart
2019-08-05 13:18 ` [PATCH v1 0/16] drm: panel related updates Emil Velikov
2019-08-05 13:18   ` Emil Velikov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191202152211.GB18532@pendragon.ideasonboard.com \
    --to=laurent.pinchart@ideasonboard.com \
    --cc=airlied@linux.ie \
    --cc=alexios.zavras@intel.com \
    --cc=alison.wang@nxp.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=gwan-gyeong.mun@intel.com \
    --cc=jonas@kwiboo.se \
    --cc=jonathanh@nvidia.com \
    --cc=kernel@pengutronix.de \
    --cc=kgene@kernel.org \
    --cc=krzk@kernel.org \
    --cc=laurent.pinchart+renesas@ideasonboard.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-imx@nxp.com \
    --cc=linux-samsung-soc@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    --cc=marex@denx.de \
    --cc=maxime.ripard@bootlin.com \
    --cc=narmstrong@baylibre.com \
    --cc=s.hauer@pengutronix.de \
    --cc=sam@ravnborg.org \
    --cc=sean@poorly.run \
    --cc=tglx@linutronix.de \
    --cc=thierry.reding@gmail.com \
    --cc=vincent.abriou@st.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.