linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 1/2] drm/dp: Add drm_dp_aux_register_ddc/chardev() helpers
@ 2021-11-07 23:08 Dmitry Osipenko
  2021-11-07 23:08 ` [PATCH v1 2/2] drm/tegra: Use " Dmitry Osipenko
  0 siblings, 1 reply; 13+ messages in thread
From: Dmitry Osipenko @ 2021-11-07 23:08 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Lyude Paul, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Daniel Vetter,
	Thomas Graichen
  Cc: dri-devel, linux-tegra, linux-kernel

Add drm_dp_aux_register_ddc/chardev() helpers that allow DP drivers
to register I2C DDC adapter and character device separately.

Cc: <stable@vger.kernel.org> # 5.13+
Reported-by: Thomas Graichen <thomas.graichen@gmail.com> # T124 Nyan Big
Tested-by: Thomas Graichen <thomas.graichen@gmail.com> # T124 Nyan Big
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/gpu/drm/drm_dp_helper.c | 112 +++++++++++++++++++++++++++-----
 include/drm/drm_dp_helper.h     |   4 ++
 2 files changed, 99 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index 4d0d1e8e51fa..56e3e57e6dc7 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -1775,7 +1775,7 @@ EXPORT_SYMBOL(drm_dp_remote_aux_init);
  * drm_dp_aux_init() - minimally initialise an aux channel
  * @aux: DisplayPort AUX channel
  *
- * If you need to use the drm_dp_aux's i2c adapter prior to registering it with
+ * If you need to use the drm_dp_aux handle prior to registering it with
  * the outside world, call drm_dp_aux_init() first. For drivers which are
  * grandparents to their AUX adapters (e.g. the AUX adapter is parented by a
  * &drm_connector), you must still call drm_dp_aux_register() once the connector
@@ -1790,6 +1790,9 @@ EXPORT_SYMBOL(drm_dp_remote_aux_init);
  */
 void drm_dp_aux_init(struct drm_dp_aux *aux)
 {
+	if (aux->ddc.algo)
+		return;
+
 	mutex_init(&aux->hw_mutex);
 	mutex_init(&aux->cec.lock);
 	INIT_WORK(&aux->crc_work, drm_dp_aux_crc_work);
@@ -1827,31 +1830,23 @@ EXPORT_SYMBOL(drm_dp_aux_init);
  * mentioned above need to call drm_dp_aux_init() in order to use the AUX
  * channel before registration.
  *
+ * Don't mix drm_dp_aux_register() with drm_dp_aux_register_chardev/ddc().
+ *
  * Returns 0 on success or a negative error code on failure.
  */
 int drm_dp_aux_register(struct drm_dp_aux *aux)
 {
 	int ret;
 
-	WARN_ON_ONCE(!aux->drm_dev);
-
-	if (!aux->ddc.algo)
-		drm_dp_aux_init(aux);
-
-	aux->ddc.class = I2C_CLASS_DDC;
-	aux->ddc.owner = THIS_MODULE;
-	aux->ddc.dev.parent = aux->dev;
+	drm_dp_aux_init(aux);
 
-	strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev),
-		sizeof(aux->ddc.name));
-
-	ret = drm_dp_aux_register_devnode(aux);
+	ret = drm_dp_aux_register_ddc(aux);
 	if (ret)
 		return ret;
 
-	ret = i2c_add_adapter(&aux->ddc);
+	ret = drm_dp_aux_register_chardev(aux);
 	if (ret) {
-		drm_dp_aux_unregister_devnode(aux);
+		drm_dp_aux_unregister_ddc(aux);
 		return ret;
 	}
 
@@ -1865,11 +1860,94 @@ EXPORT_SYMBOL(drm_dp_aux_register);
  */
 void drm_dp_aux_unregister(struct drm_dp_aux *aux)
 {
-	drm_dp_aux_unregister_devnode(aux);
-	i2c_del_adapter(&aux->ddc);
+	drm_dp_aux_unregister_chardev(aux);
+	drm_dp_aux_unregister_ddc(aux);
 }
 EXPORT_SYMBOL(drm_dp_aux_unregister);
 
+/**
+ * drm_dp_aux_register_ddc() -  initialise and register I2C DDC part of AUX channel
+ * @aux: DisplayPort AUX channel
+ *
+ * Automatically calls drm_dp_aux_init() if this hasn't been done yet.
+ * If you need to use the drm_dp_aux's I2C adapter prior to registering it with
+ * the outside world, call drm_dp_aux_register_ddc() first. For drivers which
+ * are grandparents to their AUX adapters (e.g. the AUX adapter is parented by a
+ * &drm_connector), you must still call drm_dp_aux_register_chardev() once the
+ * connector has been registered to allow userspace access to the auxiliary DP
+ * channel.
+ *
+ * For devices which use a separate platform device for their AUX adapters, this
+ * may be called as early as required by the driver.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int drm_dp_aux_register_ddc(struct drm_dp_aux *aux)
+{
+	drm_dp_aux_init(aux);
+
+	if (WARN_ON(aux->ddc.class == I2C_CLASS_DDC))
+		return -EBUSY;
+
+	aux->ddc.class = I2C_CLASS_DDC;
+	aux->ddc.owner = THIS_MODULE;
+	aux->ddc.dev.parent = aux->dev;
+
+	strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev),
+		sizeof(aux->ddc.name));
+
+	return i2c_add_adapter(&aux->ddc);
+}
+EXPORT_SYMBOL(drm_dp_aux_register_ddc);
+
+/**
+ * drm_dp_aux_unregister_ddc() - unregister I2C DDC part of AUX channel
+ * @aux: DisplayPort AUX channel
+ */
+void drm_dp_aux_unregister_ddc(struct drm_dp_aux *aux)
+{
+	i2c_del_adapter(&aux->ddc);
+
+	aux->ddc.class = 0;
+}
+EXPORT_SYMBOL(drm_dp_aux_unregister_ddc);
+
+/**
+ * drm_dp_aux_register_chardev() - initialise and register userspace part of AUX channel
+ * @aux: DisplayPort AUX channel
+ *
+ * Automatically calls drm_dp_aux_init() if this hasn't been done yet. This
+ * should only be called once the parent of @aux, &drm_dp_aux.dev, is
+ * initialized. For devices which are grandparents of their AUX channels,
+ * &drm_dp_aux.dev will typically be the &drm_connector &device which
+ * corresponds to @aux. For these devices, it's advised to call
+ * drm_dp_aux_register_chardev() in &drm_connector_funcs.late_register, and
+ * likewise to call drm_dp_aux_unregister_chardev() in
+ * &drm_connector_funcs.early_unregister. Functions which don't follow this
+ * will likely Oops when %CONFIG_DRM_DP_AUX_CHARDEV is enabled.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int drm_dp_aux_register_chardev(struct drm_dp_aux *aux)
+{
+	WARN_ON_ONCE(!aux->drm_dev);
+
+	drm_dp_aux_init(aux);
+
+	return drm_dp_aux_register_devnode(aux);
+}
+EXPORT_SYMBOL(drm_dp_aux_register_chardev);
+
+/**
+ * drm_dp_aux_unregister() - unregister userspace part of AUX channel
+ * @aux: DisplayPort AUX channel
+ */
+void drm_dp_aux_unregister_chardev(struct drm_dp_aux *aux)
+{
+	drm_dp_aux_unregister_devnode(aux);
+}
+EXPORT_SYMBOL(drm_dp_aux_unregister_chardev);
+
 #define PSR_SETUP_TIME(x) [DP_PSR_SETUP_TIME_ ## x >> DP_PSR_SETUP_TIME_SHIFT] = (x)
 
 /**
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index b52df4db3e8f..80130458188d 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -2130,6 +2130,10 @@ void drm_dp_remote_aux_init(struct drm_dp_aux *aux);
 void drm_dp_aux_init(struct drm_dp_aux *aux);
 int drm_dp_aux_register(struct drm_dp_aux *aux);
 void drm_dp_aux_unregister(struct drm_dp_aux *aux);
+int drm_dp_aux_register_ddc(struct drm_dp_aux *aux);
+void drm_dp_aux_unregister_ddc(struct drm_dp_aux *aux);
+int drm_dp_aux_register_chardev(struct drm_dp_aux *aux);
+void drm_dp_aux_unregister_chardev(struct drm_dp_aux *aux);
 
 int drm_dp_start_crc(struct drm_dp_aux *aux, struct drm_crtc *crtc);
 int drm_dp_stop_crc(struct drm_dp_aux *aux);
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v1 2/2] drm/tegra: Use drm_dp_aux_register_ddc/chardev() helpers
  2021-11-07 23:08 [PATCH v1 1/2] drm/dp: Add drm_dp_aux_register_ddc/chardev() helpers Dmitry Osipenko
@ 2021-11-07 23:08 ` Dmitry Osipenko
  2021-11-08 15:17   ` Daniel Vetter
  0 siblings, 1 reply; 13+ messages in thread
From: Dmitry Osipenko @ 2021-11-07 23:08 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Lyude Paul, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Daniel Vetter,
	Thomas Graichen
  Cc: dri-devel, linux-tegra, linux-kernel

Use drm_dp_aux_register_ddc/chardev() helpers that allow to register I2C
adapter separately from the character device. This fixes broken display
panel driver of Acer Chromebook CB5-311 that fails to probe starting with
v5.13 kernel when DP AUX registration order was changed. Tegra SOR driver
is never probed now using the new registration order because tegra-output
always fails with -EPROBE_DEFER due to missing display panel that requires
DP AUX DDC to be registered first. The offending commit made DDC to be
registered after SOR's output, which can't ever happen. Use new helpers
to restore the registration order and revive display panel.

Cc: <stable@vger.kernel.org> # 5.13+
Fixes: 39c17ae60ea9 ("drm/tegra: Don't register DP AUX channels before connectors")
Reported-by: Thomas Graichen <thomas.graichen@gmail.com> # T124 Nyan Big
Tested-by: Thomas Graichen <thomas.graichen@gmail.com> # T124 Nyan Big
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/gpu/drm/tegra/dpaux.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c
index 1f96e416fa08..e0d675c7c2e5 100644
--- a/drivers/gpu/drm/tegra/dpaux.c
+++ b/drivers/gpu/drm/tegra/dpaux.c
@@ -532,7 +532,9 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
 	dpaux->aux.transfer = tegra_dpaux_transfer;
 	dpaux->aux.dev = &pdev->dev;
 
-	drm_dp_aux_init(&dpaux->aux);
+	err = drm_dp_aux_register_ddc(&dpaux->aux);
+	if (err < 0)
+		return err;
 
 	/*
 	 * Assume that by default the DPAUX/I2C pads will be used for HDMI,
@@ -585,6 +587,8 @@ static int tegra_dpaux_remove(struct platform_device *pdev)
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 
+	drm_dp_aux_unregister_ddc(&dpaux->aux);
+
 	mutex_lock(&dpaux_lock);
 	list_del(&dpaux->list);
 	mutex_unlock(&dpaux_lock);
@@ -718,7 +722,7 @@ int drm_dp_aux_attach(struct drm_dp_aux *aux, struct tegra_output *output)
 	int err;
 
 	aux->drm_dev = output->connector.dev;
-	err = drm_dp_aux_register(aux);
+	err = drm_dp_aux_register_chardev(aux);
 	if (err < 0)
 		return err;
 
@@ -759,7 +763,7 @@ int drm_dp_aux_detach(struct drm_dp_aux *aux)
 	unsigned long timeout;
 	int err;
 
-	drm_dp_aux_unregister(aux);
+	drm_dp_aux_unregister_chardev(aux);
 	disable_irq(dpaux->irq);
 
 	if (dpaux->output->panel) {
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v1 2/2] drm/tegra: Use drm_dp_aux_register_ddc/chardev() helpers
  2021-11-07 23:08 ` [PATCH v1 2/2] drm/tegra: Use " Dmitry Osipenko
@ 2021-11-08 15:17   ` Daniel Vetter
  2021-11-08 18:16     ` Dmitry Osipenko
  0 siblings, 1 reply; 13+ messages in thread
From: Daniel Vetter @ 2021-11-08 15:17 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Thierry Reding, Jonathan Hunter, Lyude Paul, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Daniel Vetter,
	Thomas Graichen, dri-devel, linux-tegra, linux-kernel

On Mon, Nov 08, 2021 at 02:08:21AM +0300, Dmitry Osipenko wrote:
> Use drm_dp_aux_register_ddc/chardev() helpers that allow to register I2C
> adapter separately from the character device. This fixes broken display
> panel driver of Acer Chromebook CB5-311 that fails to probe starting with
> v5.13 kernel when DP AUX registration order was changed. Tegra SOR driver
> is never probed now using the new registration order because tegra-output
> always fails with -EPROBE_DEFER due to missing display panel that requires
> DP AUX DDC to be registered first. The offending commit made DDC to be
> registered after SOR's output, which can't ever happen. Use new helpers
> to restore the registration order and revive display panel.

This feels a bit backward, I think the clean solution would be to untangle
the SOR loading from the panel driver loading, and then only block
registering the overall drm_device on both drivers having loaded.

This here at least feels like a game of whack-a-mole, if like every driver
needs its own careful staging of everything.
-Daniel

> 
> Cc: <stable@vger.kernel.org> # 5.13+
> Fixes: 39c17ae60ea9 ("drm/tegra: Don't register DP AUX channels before connectors")
> Reported-by: Thomas Graichen <thomas.graichen@gmail.com> # T124 Nyan Big
> Tested-by: Thomas Graichen <thomas.graichen@gmail.com> # T124 Nyan Big
> Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
> ---
>  drivers/gpu/drm/tegra/dpaux.c | 10 +++++++---
>  1 file changed, 7 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c
> index 1f96e416fa08..e0d675c7c2e5 100644
> --- a/drivers/gpu/drm/tegra/dpaux.c
> +++ b/drivers/gpu/drm/tegra/dpaux.c
> @@ -532,7 +532,9 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
>  	dpaux->aux.transfer = tegra_dpaux_transfer;
>  	dpaux->aux.dev = &pdev->dev;
>  
> -	drm_dp_aux_init(&dpaux->aux);
> +	err = drm_dp_aux_register_ddc(&dpaux->aux);
> +	if (err < 0)
> +		return err;
>  
>  	/*
>  	 * Assume that by default the DPAUX/I2C pads will be used for HDMI,
> @@ -585,6 +587,8 @@ static int tegra_dpaux_remove(struct platform_device *pdev)
>  	pm_runtime_put_sync(&pdev->dev);
>  	pm_runtime_disable(&pdev->dev);
>  
> +	drm_dp_aux_unregister_ddc(&dpaux->aux);
> +
>  	mutex_lock(&dpaux_lock);
>  	list_del(&dpaux->list);
>  	mutex_unlock(&dpaux_lock);
> @@ -718,7 +722,7 @@ int drm_dp_aux_attach(struct drm_dp_aux *aux, struct tegra_output *output)
>  	int err;
>  
>  	aux->drm_dev = output->connector.dev;
> -	err = drm_dp_aux_register(aux);
> +	err = drm_dp_aux_register_chardev(aux);
>  	if (err < 0)
>  		return err;
>  
> @@ -759,7 +763,7 @@ int drm_dp_aux_detach(struct drm_dp_aux *aux)
>  	unsigned long timeout;
>  	int err;
>  
> -	drm_dp_aux_unregister(aux);
> +	drm_dp_aux_unregister_chardev(aux);
>  	disable_irq(dpaux->irq);
>  
>  	if (dpaux->output->panel) {
> -- 
> 2.33.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v1 2/2] drm/tegra: Use drm_dp_aux_register_ddc/chardev() helpers
  2021-11-08 15:17   ` Daniel Vetter
@ 2021-11-08 18:16     ` Dmitry Osipenko
  2021-11-09  9:19       ` Daniel Vetter
  0 siblings, 1 reply; 13+ messages in thread
From: Dmitry Osipenko @ 2021-11-08 18:16 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Lyude Paul, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Thomas Graichen,
	dri-devel, linux-tegra, linux-kernel

08.11.2021 18:17, Daniel Vetter пишет:
> On Mon, Nov 08, 2021 at 02:08:21AM +0300, Dmitry Osipenko wrote:
>> Use drm_dp_aux_register_ddc/chardev() helpers that allow to register I2C
>> adapter separately from the character device. This fixes broken display
>> panel driver of Acer Chromebook CB5-311 that fails to probe starting with
>> v5.13 kernel when DP AUX registration order was changed. Tegra SOR driver
>> is never probed now using the new registration order because tegra-output
>> always fails with -EPROBE_DEFER due to missing display panel that requires
>> DP AUX DDC to be registered first. The offending commit made DDC to be
>> registered after SOR's output, which can't ever happen. Use new helpers
>> to restore the registration order and revive display panel.
> 
> This feels a bit backward, I think the clean solution would be to untangle
> the SOR loading from the panel driver loading, and then only block
> registering the overall drm_device on both drivers having loaded.

Sounds impossible.

1. DRM device can be created only when all components are ready, panel
is one of the components.

2. SOR driver is controlling panel and programs h/w based on panel presence.

3. Panel can't become ready until DP AUX DDC is created.

4. DP AUX DDC can't be created until DRM device is created.

5. Go to 1.

Even if there is an option to somehow rewrite Tegra DRM driver to
accommodate it to the desired driver model, it won't be something
portable to stable kernels.

> This here at least feels like a game of whack-a-mole, if like every driver
> needs its own careful staging of everything.

That is inevitable because each hardware design is individual.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v1 2/2] drm/tegra: Use drm_dp_aux_register_ddc/chardev() helpers
  2021-11-08 18:16     ` Dmitry Osipenko
@ 2021-11-09  9:19       ` Daniel Vetter
  2021-11-09 13:52         ` Dmitry Osipenko
  0 siblings, 1 reply; 13+ messages in thread
From: Daniel Vetter @ 2021-11-09  9:19 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Thierry Reding, Jonathan Hunter, Lyude Paul, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Thomas Graichen,
	dri-devel, linux-tegra, linux-kernel

On Mon, Nov 08, 2021 at 09:16:07PM +0300, Dmitry Osipenko wrote:
> 08.11.2021 18:17, Daniel Vetter пишет:
> > On Mon, Nov 08, 2021 at 02:08:21AM +0300, Dmitry Osipenko wrote:
> >> Use drm_dp_aux_register_ddc/chardev() helpers that allow to register I2C
> >> adapter separately from the character device. This fixes broken display
> >> panel driver of Acer Chromebook CB5-311 that fails to probe starting with
> >> v5.13 kernel when DP AUX registration order was changed. Tegra SOR driver
> >> is never probed now using the new registration order because tegra-output
> >> always fails with -EPROBE_DEFER due to missing display panel that requires
> >> DP AUX DDC to be registered first. The offending commit made DDC to be
> >> registered after SOR's output, which can't ever happen. Use new helpers
> >> to restore the registration order and revive display panel.
> > 
> > This feels a bit backward, I think the clean solution would be to untangle
> > the SOR loading from the panel driver loading, and then only block
> > registering the overall drm_device on both drivers having loaded.
> 
> Sounds impossible.
> 
> 1. DRM device can be created only when all components are ready, panel
> is one of the components.

Nope. drm_device can be instantiated whenever you feel like.
drm_dev_register can only be called when it's all fully set up. Absolutely
nothing would work if drm_device wouldn't support this two-stage setup.

So sequence:

1. drm_dev_init

2. bind sor driver

3. create dp aux ddc

4. bind panel

5. yay we have everything, drm_dev_register

This should work, and it's designed to work like this actually. You
couldn't write big complex drivers otherwise.
-Daniel

> 
> 2. SOR driver is controlling panel and programs h/w based on panel presence.
> 
> 3. Panel can't become ready until DP AUX DDC is created.
> 
> 4. DP AUX DDC can't be created until DRM device is created.
> 
> 5. Go to 1.
> 
> Even if there is an option to somehow rewrite Tegra DRM driver to
> accommodate it to the desired driver model, it won't be something
> portable to stable kernels.
> 
> > This here at least feels like a game of whack-a-mole, if like every driver
> > needs its own careful staging of everything.
> 
> That is inevitable because each hardware design is individual.

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v1 2/2] drm/tegra: Use drm_dp_aux_register_ddc/chardev() helpers
  2021-11-09  9:19       ` Daniel Vetter
@ 2021-11-09 13:52         ` Dmitry Osipenko
  2021-11-09 14:08           ` Dmitry Osipenko
  0 siblings, 1 reply; 13+ messages in thread
From: Dmitry Osipenko @ 2021-11-09 13:52 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Lyude Paul, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Thomas Graichen,
	dri-devel, linux-tegra, linux-kernel

09.11.2021 12:19, Daniel Vetter пишет:
> On Mon, Nov 08, 2021 at 09:16:07PM +0300, Dmitry Osipenko wrote:
>> 08.11.2021 18:17, Daniel Vetter пишет:
>>> On Mon, Nov 08, 2021 at 02:08:21AM +0300, Dmitry Osipenko wrote:
>>>> Use drm_dp_aux_register_ddc/chardev() helpers that allow to register I2C
>>>> adapter separately from the character device. This fixes broken display
>>>> panel driver of Acer Chromebook CB5-311 that fails to probe starting with
>>>> v5.13 kernel when DP AUX registration order was changed. Tegra SOR driver
>>>> is never probed now using the new registration order because tegra-output
>>>> always fails with -EPROBE_DEFER due to missing display panel that requires
>>>> DP AUX DDC to be registered first. The offending commit made DDC to be
>>>> registered after SOR's output, which can't ever happen. Use new helpers
>>>> to restore the registration order and revive display panel.
>>>
>>> This feels a bit backward, I think the clean solution would be to untangle
>>> the SOR loading from the panel driver loading, and then only block
>>> registering the overall drm_device on both drivers having loaded.
>>
>> Sounds impossible.
>>
>> 1. DRM device can be created only when all components are ready, panel
>> is one of the components.
> 
> Nope. drm_device can be instantiated whenever you feel like.
> drm_dev_register can only be called when it's all fully set up. Absolutely
> nothing would work if drm_device wouldn't support this two-stage setup.
> 
> So sequence:
> 
> 1. drm_dev_init
> 
> 2. bind sor driver
> 
> 3. create dp aux ddc
> 
> 4. bind panel
> 
> 5. yay we have everything, drm_dev_register
> 
> This should work, and it's designed to work like this actually. You
> couldn't write big complex drivers otherwise.

All Tegra SoCs have graphics bus named Host1x, that is where components
comprising DRM driver are sitting on.

The Tegra driver model works like this:

1. Once Host1x driver is loaded, it populates children sub-nodes of
Host1x device-tree node, this creates Tegra DRM platform sub-devices.

2. Tegra DRM driver module-init call registers main "Host1x DRM" driver
and platform sub-drivers. Now Host1x bus knows what devices comprise
Tegra DRM because Host1x driver descriptor contains that info.

3. Tegra DRM platform sub-drivers are bound to the sub-devices.

4. Once Host1x bus sees that all Tegra DRM sub-drivers are bound, it
creates Host1x DRM device.

5. The Host1x DRM device is bound to the Host1x DRM driver and
host1x_drm_probe(host1x_dev) is invoked, which does the following:

	drm_dev_alloc(driver, host1x_dev)
	host1x_device_init(host1x_dev)
	drm_dev_register(drm).

6. The host1x_device_init() invokes second stage initialization of Tegra
DRM sub-drivers, that is init() callback of host1x_client_ops registered
by DRM platform sub-drivers during theirs probe.

The DP AUX DDC is currently created in step 6, while it should be
created in step 3, otherwise SOR driver can't be bound.

It's possible to add early-init stage to the Host1x driver model where
DRM device can be created before DRM platform sub-drivers are registered
and probed. This is ad-hoc solution, but it should work okay in practice.

I can make v2 if you and Thierry are okay with that solution, see it below.

--- 8< ---

diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c
index 1f96e416fa08..9e17a75a1383 100644
--- a/drivers/gpu/drm/tegra/dpaux.c
+++ b/drivers/gpu/drm/tegra/dpaux.c
@@ -530,9 +530,12 @@ static int tegra_dpaux_probe(struct platform_device
*pdev)
 	disable_irq(dpaux->irq);

 	dpaux->aux.transfer = tegra_dpaux_transfer;
+	dpaux->aux.drm_dev = tegra_drm_device();
 	dpaux->aux.dev = &pdev->dev;

-	drm_dp_aux_init(&dpaux->aux);
+	err = drm_dp_aux_register(&dpaux->aux);
+	if (err < 0)
+		return err;

 	/*
 	 * Assume that by default the DPAUX/I2C pads will be used for HDMI,
@@ -585,6 +588,8 @@ static int tegra_dpaux_remove(struct platform_device
*pdev)
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);

+	drm_dp_aux_unregister(&dpaux->aux);
+
 	mutex_lock(&dpaux_lock);
 	list_del(&dpaux->list);
 	mutex_unlock(&dpaux_lock);
@@ -717,11 +722,6 @@ int drm_dp_aux_attach(struct drm_dp_aux *aux,
struct tegra_output *output)
 	unsigned long timeout;
 	int err;

-	aux->drm_dev = output->connector.dev;
-	err = drm_dp_aux_register(aux);
-	if (err < 0)
-		return err;
-
 	output->connector.polled = DRM_CONNECTOR_POLL_HPD;
 	dpaux->output = output;

@@ -759,7 +759,6 @@ int drm_dp_aux_detach(struct drm_dp_aux *aux)
 	unsigned long timeout;
 	int err;

-	drm_dp_aux_unregister(aux);
 	disable_irq(dpaux->irq);

 	if (dpaux->output->panel) {
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index b2ebba802107..d95f9dea6b86 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -1124,21 +1124,42 @@ static bool host1x_drm_wants_iommu(struct
host1x_device *dev)
 	return domain != NULL;
 }

-static int host1x_drm_probe(struct host1x_device *dev)
+static struct drm_device *terga_drm_dev;
+
+struct drm_device *tegra_drm_device(void)
 {
-	struct tegra_drm *tegra;
-	struct drm_device *drm;
-	int err;
+	return terga_drm_dev;
+}

-	drm = drm_dev_alloc(&tegra_drm_driver, &dev->dev);
+static int host1x_drm_dev_init(struct host1x_device *dev)
+{
+	struct drm_device *drm = drm_dev_alloc(&tegra_drm_driver, &dev->dev);
 	if (IS_ERR(drm))
 		return PTR_ERR(drm);

+	dev_set_drvdata(&dev->dev, drm);
+	terga_drm_dev = drm;
+
+	return 0;
+}
+
+static void host1x_drm_dev_deinit(struct host1x_device *dev)
+{
+	struct drm_device *drm = dev_get_drvdata(&dev->dev);
+
+	terga_drm_dev = NULL;
+	drm_dev_put(drm);
+}
+
+static int host1x_drm_probe(struct host1x_device *dev)
+{
+	struct drm_device *drm = dev_get_drvdata(&dev->dev);
+	struct tegra_drm *tegra;
+	int err;
+
 	tegra = kzalloc(sizeof(*tegra), GFP_KERNEL);
-	if (!tegra) {
-		err = -ENOMEM;
-		goto put;
-	}
+	if (!tegra)
+		return -ENOMEM;

 	if (host1x_drm_wants_iommu(dev) && iommu_present(&platform_bus_type)) {
 		tegra->domain = iommu_domain_alloc(&platform_bus_type);
@@ -1155,7 +1176,6 @@ static int host1x_drm_probe(struct host1x_device *dev)
 	mutex_init(&tegra->clients_lock);
 	INIT_LIST_HEAD(&tegra->clients);

-	dev_set_drvdata(&dev->dev, drm);
 	drm->dev_private = tegra;
 	tegra->drm = drm;

@@ -1276,8 +1296,7 @@ static int host1x_drm_probe(struct host1x_device *dev)
 		iommu_domain_free(tegra->domain);
 free:
 	kfree(tegra);
-put:
-	drm_dev_put(drm);
+
 	return err;
 }

@@ -1310,7 +1329,6 @@ static int host1x_drm_remove(struct host1x_device
*dev)
 	}

 	kfree(tegra);
-	drm_dev_put(drm);

 	return 0;
 }
@@ -1382,6 +1400,8 @@ static struct host1x_driver host1x_drm_driver = {
 	.probe = host1x_drm_probe,
 	.remove = host1x_drm_remove,
 	.subdevs = host1x_drm_subdevs,
+	.init = host1x_drm_dev_init,
+	.deinit = host1x_drm_dev_deinit,
 };

 static struct platform_driver * const drivers[] = {
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index fc0a19554eac..4bfe79b5c7ce 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -64,6 +64,8 @@ struct tegra_drm {
 	struct tegra_display_hub *hub;
 };

+struct drm_device *tegra_drm_device(void);
+
 static inline struct host1x *tegra_drm_to_host1x(struct tegra_drm *tegra)
 {
 	return dev_get_drvdata(tegra->drm->dev->parent);
diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c
index 0d81eede1217..25d688e5c742 100644
--- a/drivers/gpu/host1x/bus.c
+++ b/drivers/gpu/host1x/bus.c
@@ -479,8 +479,18 @@ static int host1x_device_add(struct host1x *host1x,
 	device->dev.dma_parms = &device->dma_parms;
 	dma_set_max_seg_size(&device->dev, UINT_MAX);

+	if (driver->init) {
+		err = driver->init(device);
+		if (err < 0) {
+			kfree(device);
+			return err;
+		}
+	}
+
 	err = host1x_device_parse_dt(device, driver);
 	if (err < 0) {
+		if (driver->deinit)
+			driver->deinit(device);
 		kfree(device);
 		return err;
 	}
@@ -512,11 +522,16 @@ static int host1x_device_add(struct host1x *host1x,
 static void host1x_device_del(struct host1x *host1x,
 			      struct host1x_device *device)
 {
+	struct host1x_driver *driver = device->driver;
+
 	if (device->registered) {
 		device->registered = false;
 		device_del(&device->dev);
 	}

+	if (driver->deinit)
+		driver->deinit(device);
+
 	put_device(&device->dev);
 }

diff --git a/include/linux/host1x.h b/include/linux/host1x.h
index e8dc5bc41f79..5e5ba33af4ae 100644
--- a/include/linux/host1x.h
+++ b/include/linux/host1x.h
@@ -346,6 +346,8 @@ struct host1x_device;
  * @driver: core driver
  * @subdevs: table of OF device IDs matching subdevices for this driver
  * @list: list node for the driver
+ * @init: called when the host1x logical driver is registered
+ * @deinit: called when the host1x logical driver is unregistered
  * @probe: called when the host1x logical device is probed
  * @remove: called when the host1x logical device is removed
  * @shutdown: called when the host1x logical device is shut down
@@ -356,6 +358,8 @@ struct host1x_driver {
 	const struct of_device_id *subdevs;
 	struct list_head list;

+	int (*init)(struct host1x_device *device);
+	void (*deinit)(struct host1x_device *device);
 	int (*probe)(struct host1x_device *device);
 	int (*remove)(struct host1x_device *device);
 	void (*shutdown)(struct host1x_device *device);

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v1 2/2] drm/tegra: Use drm_dp_aux_register_ddc/chardev() helpers
  2021-11-09 13:52         ` Dmitry Osipenko
@ 2021-11-09 14:08           ` Dmitry Osipenko
  2021-11-09 14:17             ` Dmitry Osipenko
  0 siblings, 1 reply; 13+ messages in thread
From: Dmitry Osipenko @ 2021-11-09 14:08 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Lyude Paul, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Thomas Graichen,
	dri-devel, linux-tegra, linux-kernel

09.11.2021 16:52, Dmitry Osipenko пишет:
> 09.11.2021 12:19, Daniel Vetter пишет:
>> On Mon, Nov 08, 2021 at 09:16:07PM +0300, Dmitry Osipenko wrote:
>>> 08.11.2021 18:17, Daniel Vetter пишет:
>>>> On Mon, Nov 08, 2021 at 02:08:21AM +0300, Dmitry Osipenko wrote:
>>>>> Use drm_dp_aux_register_ddc/chardev() helpers that allow to register I2C
>>>>> adapter separately from the character device. This fixes broken display
>>>>> panel driver of Acer Chromebook CB5-311 that fails to probe starting with
>>>>> v5.13 kernel when DP AUX registration order was changed. Tegra SOR driver
>>>>> is never probed now using the new registration order because tegra-output
>>>>> always fails with -EPROBE_DEFER due to missing display panel that requires
>>>>> DP AUX DDC to be registered first. The offending commit made DDC to be
>>>>> registered after SOR's output, which can't ever happen. Use new helpers
>>>>> to restore the registration order and revive display panel.
>>>>
>>>> This feels a bit backward, I think the clean solution would be to untangle
>>>> the SOR loading from the panel driver loading, and then only block
>>>> registering the overall drm_device on both drivers having loaded.
>>>
>>> Sounds impossible.
>>>
>>> 1. DRM device can be created only when all components are ready, panel
>>> is one of the components.
>>
>> Nope. drm_device can be instantiated whenever you feel like.
>> drm_dev_register can only be called when it's all fully set up. Absolutely
>> nothing would work if drm_device wouldn't support this two-stage setup.
>>
>> So sequence:
>>
>> 1. drm_dev_init
>>
>> 2. bind sor driver
>>
>> 3. create dp aux ddc
>>
>> 4. bind panel
>>
>> 5. yay we have everything, drm_dev_register
>>
>> This should work, and it's designed to work like this actually. You
>> couldn't write big complex drivers otherwise.
> 
> All Tegra SoCs have graphics bus named Host1x, that is where components
> comprising DRM driver are sitting on.
> 
> The Tegra driver model works like this:
> 
> 1. Once Host1x driver is loaded, it populates children sub-nodes of
> Host1x device-tree node, this creates Tegra DRM platform sub-devices.
> 
> 2. Tegra DRM driver module-init call registers main "Host1x DRM" driver
> and platform sub-drivers. Now Host1x bus knows what devices comprise
> Tegra DRM because Host1x driver descriptor contains that info.
> 
> 3. Tegra DRM platform sub-drivers are bound to the sub-devices.
> 
> 4. Once Host1x bus sees that all Tegra DRM sub-drivers are bound, it
> creates Host1x DRM device.
> 
> 5. The Host1x DRM device is bound to the Host1x DRM driver and
> host1x_drm_probe(host1x_dev) is invoked, which does the following:
> 
> 	drm_dev_alloc(driver, host1x_dev)
> 	host1x_device_init(host1x_dev)
> 	drm_dev_register(drm).
> 
> 6. The host1x_device_init() invokes second stage initialization of Tegra
> DRM sub-drivers, that is init() callback of host1x_client_ops registered
> by DRM platform sub-drivers during theirs probe.
> 
> The DP AUX DDC is currently created in step 6, while it should be
> created in step 3, otherwise SOR driver can't be bound.
> 
> It's possible to add early-init stage to the Host1x driver model where
> DRM device can be created before DRM platform sub-drivers are registered
> and probed. This is ad-hoc solution, but it should work okay in practice.
> 
> I can make v2 if you and Thierry are okay with that solution, see it below.
> 
> --- 8< ---
> 
> diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c
> index 1f96e416fa08..9e17a75a1383 100644
> --- a/drivers/gpu/drm/tegra/dpaux.c
> +++ b/drivers/gpu/drm/tegra/dpaux.c
> @@ -530,9 +530,12 @@ static int tegra_dpaux_probe(struct platform_device
> *pdev)
>  	disable_irq(dpaux->irq);
> 
>  	dpaux->aux.transfer = tegra_dpaux_transfer;
> +	dpaux->aux.drm_dev = tegra_drm_device();
>  	dpaux->aux.dev = &pdev->dev;
> 
> -	drm_dp_aux_init(&dpaux->aux);
> +	err = drm_dp_aux_register(&dpaux->aux);
> +	if (err < 0)
> +		return err;
> 
>  	/*
>  	 * Assume that by default the DPAUX/I2C pads will be used for HDMI,
> @@ -585,6 +588,8 @@ static int tegra_dpaux_remove(struct platform_device
> *pdev)
>  	pm_runtime_put_sync(&pdev->dev);
>  	pm_runtime_disable(&pdev->dev);
> 
> +	drm_dp_aux_unregister(&dpaux->aux);
> +
>  	mutex_lock(&dpaux_lock);
>  	list_del(&dpaux->list);
>  	mutex_unlock(&dpaux_lock);
> @@ -717,11 +722,6 @@ int drm_dp_aux_attach(struct drm_dp_aux *aux,
> struct tegra_output *output)
>  	unsigned long timeout;
>  	int err;
> 
> -	aux->drm_dev = output->connector.dev;
> -	err = drm_dp_aux_register(aux);
> -	if (err < 0)
> -		return err;
> -
>  	output->connector.polled = DRM_CONNECTOR_POLL_HPD;
>  	dpaux->output = output;
> 
> @@ -759,7 +759,6 @@ int drm_dp_aux_detach(struct drm_dp_aux *aux)
>  	unsigned long timeout;
>  	int err;
> 
> -	drm_dp_aux_unregister(aux);
>  	disable_irq(dpaux->irq);
> 
>  	if (dpaux->output->panel) {
> diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
> index b2ebba802107..d95f9dea6b86 100644
> --- a/drivers/gpu/drm/tegra/drm.c
> +++ b/drivers/gpu/drm/tegra/drm.c
> @@ -1124,21 +1124,42 @@ static bool host1x_drm_wants_iommu(struct
> host1x_device *dev)
>  	return domain != NULL;
>  }
> 
> -static int host1x_drm_probe(struct host1x_device *dev)
> +static struct drm_device *terga_drm_dev;
> +
> +struct drm_device *tegra_drm_device(void)
>  {
> -	struct tegra_drm *tegra;
> -	struct drm_device *drm;
> -	int err;
> +	return terga_drm_dev;
> +}
> 
> -	drm = drm_dev_alloc(&tegra_drm_driver, &dev->dev);
> +static int host1x_drm_dev_init(struct host1x_device *dev)
> +{
> +	struct drm_device *drm = drm_dev_alloc(&tegra_drm_driver, &dev->dev);
>  	if (IS_ERR(drm))
>  		return PTR_ERR(drm);
> 
> +	dev_set_drvdata(&dev->dev, drm);
> +	terga_drm_dev = drm;

Although, platform_register_drivers() should be moved here out from
host1x_drm_init(), otherwise DRM drivers may get probed before main
host1x driver is registered and then terga_drm_dev will be NULL. But you
should get the idea anyways.

> +	return 0;
> +}
> +
> +static void host1x_drm_dev_deinit(struct host1x_device *dev)
> +{
> +	struct drm_device *drm = dev_get_drvdata(&dev->dev);

And platform_unregister_drivers() should be moved here.

> +	terga_drm_dev = NULL;
> +	drm_dev_put(drm);
> +}
> +
> +static int host1x_drm_probe(struct host1x_device *dev)
> +{
> +	struct drm_device *drm = dev_get_drvdata(&dev->dev);
> +	struct tegra_drm *tegra;
> +	int err;
> +
>  	tegra = kzalloc(sizeof(*tegra), GFP_KERNEL);
> -	if (!tegra) {
> -		err = -ENOMEM;
> -		goto put;
> -	}
> +	if (!tegra)
> +		return -ENOMEM;
> 
>  	if (host1x_drm_wants_iommu(dev) && iommu_present(&platform_bus_type)) {
>  		tegra->domain = iommu_domain_alloc(&platform_bus_type);
> @@ -1155,7 +1176,6 @@ static int host1x_drm_probe(struct host1x_device *dev)
>  	mutex_init(&tegra->clients_lock);
>  	INIT_LIST_HEAD(&tegra->clients);
> 
> -	dev_set_drvdata(&dev->dev, drm);
>  	drm->dev_private = tegra;
>  	tegra->drm = drm;
> 
> @@ -1276,8 +1296,7 @@ static int host1x_drm_probe(struct host1x_device *dev)
>  		iommu_domain_free(tegra->domain);
>  free:
>  	kfree(tegra);
> -put:
> -	drm_dev_put(drm);
> +
>  	return err;
>  }
> 
> @@ -1310,7 +1329,6 @@ static int host1x_drm_remove(struct host1x_device
> *dev)
>  	}
> 
>  	kfree(tegra);
> -	drm_dev_put(drm);
> 
>  	return 0;
>  }
> @@ -1382,6 +1400,8 @@ static struct host1x_driver host1x_drm_driver = {
>  	.probe = host1x_drm_probe,
>  	.remove = host1x_drm_remove,
>  	.subdevs = host1x_drm_subdevs,
> +	.init = host1x_drm_dev_init,
> +	.deinit = host1x_drm_dev_deinit,
>  };
> 
>  static struct platform_driver * const drivers[] = {
> diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
> index fc0a19554eac..4bfe79b5c7ce 100644
> --- a/drivers/gpu/drm/tegra/drm.h
> +++ b/drivers/gpu/drm/tegra/drm.h
> @@ -64,6 +64,8 @@ struct tegra_drm {
>  	struct tegra_display_hub *hub;
>  };
> 
> +struct drm_device *tegra_drm_device(void);
> +
>  static inline struct host1x *tegra_drm_to_host1x(struct tegra_drm *tegra)
>  {
>  	return dev_get_drvdata(tegra->drm->dev->parent);
> diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c
> index 0d81eede1217..25d688e5c742 100644
> --- a/drivers/gpu/host1x/bus.c
> +++ b/drivers/gpu/host1x/bus.c
> @@ -479,8 +479,18 @@ static int host1x_device_add(struct host1x *host1x,
>  	device->dev.dma_parms = &device->dma_parms;
>  	dma_set_max_seg_size(&device->dev, UINT_MAX);
> 
> +	if (driver->init) {
> +		err = driver->init(device);
> +		if (err < 0) {
> +			kfree(device);
> +			return err;
> +		}
> +	}
> +
>  	err = host1x_device_parse_dt(device, driver);
>  	if (err < 0) {
> +		if (driver->deinit)
> +			driver->deinit(device);
>  		kfree(device);
>  		return err;
>  	}
> @@ -512,11 +522,16 @@ static int host1x_device_add(struct host1x *host1x,
>  static void host1x_device_del(struct host1x *host1x,
>  			      struct host1x_device *device)
>  {
> +	struct host1x_driver *driver = device->driver;
> +
>  	if (device->registered) {
>  		device->registered = false;
>  		device_del(&device->dev);
>  	}
> 
> +	if (driver->deinit)
> +		driver->deinit(device);
> +
>  	put_device(&device->dev);
>  }
> 
> diff --git a/include/linux/host1x.h b/include/linux/host1x.h
> index e8dc5bc41f79..5e5ba33af4ae 100644
> --- a/include/linux/host1x.h
> +++ b/include/linux/host1x.h
> @@ -346,6 +346,8 @@ struct host1x_device;
>   * @driver: core driver
>   * @subdevs: table of OF device IDs matching subdevices for this driver
>   * @list: list node for the driver
> + * @init: called when the host1x logical driver is registered
> + * @deinit: called when the host1x logical driver is unregistered
>   * @probe: called when the host1x logical device is probed
>   * @remove: called when the host1x logical device is removed
>   * @shutdown: called when the host1x logical device is shut down
> @@ -356,6 +358,8 @@ struct host1x_driver {
>  	const struct of_device_id *subdevs;
>  	struct list_head list;
> 
> +	int (*init)(struct host1x_device *device);
> +	void (*deinit)(struct host1x_device *device);
>  	int (*probe)(struct host1x_device *device);
>  	int (*remove)(struct host1x_device *device);
>  	void (*shutdown)(struct host1x_device *device);
> 


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v1 2/2] drm/tegra: Use drm_dp_aux_register_ddc/chardev() helpers
  2021-11-09 14:08           ` Dmitry Osipenko
@ 2021-11-09 14:17             ` Dmitry Osipenko
  2021-11-09 14:39               ` Dmitry Osipenko
  0 siblings, 1 reply; 13+ messages in thread
From: Dmitry Osipenko @ 2021-11-09 14:17 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Lyude Paul, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Thomas Graichen,
	dri-devel, linux-tegra, linux-kernel

09.11.2021 17:08, Dmitry Osipenko пишет:
>> +static void host1x_drm_dev_deinit(struct host1x_device *dev)
>> +{
>> +	struct drm_device *drm = dev_get_drvdata(&dev->dev);
> And platform_unregister_drivers() should be moved here.
> 

Nah, that should cause deadlock. This ad-hoc is too lame.

Another solution is to defer probing of DP AUX driver while
tegra_drm_device() returns NULL, but it's icky.

Reverting the original DP AUX DDC registration order is the best option
so far, IMO.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v1 2/2] drm/tegra: Use drm_dp_aux_register_ddc/chardev() helpers
  2021-11-09 14:17             ` Dmitry Osipenko
@ 2021-11-09 14:39               ` Dmitry Osipenko
  2021-11-12 10:52                 ` Thierry Reding
  0 siblings, 1 reply; 13+ messages in thread
From: Dmitry Osipenko @ 2021-11-09 14:39 UTC (permalink / raw)
  To: Thierry Reding, Jonathan Hunter, Lyude Paul, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Thomas Graichen,
	dri-devel, linux-tegra, linux-kernel

09.11.2021 17:17, Dmitry Osipenko пишет:
> 09.11.2021 17:08, Dmitry Osipenko пишет:
>>> +static void host1x_drm_dev_deinit(struct host1x_device *dev)
>>> +{
>>> +	struct drm_device *drm = dev_get_drvdata(&dev->dev);
>> And platform_unregister_drivers() should be moved here.
>>
> 
> Nah, that should cause deadlock. This ad-hoc is too lame.

Actually, there is no problem here as I see now. The host1x driver
populates DT nodes after host1x_register() [1], meaning that Host1x DRM
will be always inited first.

[1]
https://elixir.bootlin.com/linux/v5.15/source/drivers/gpu/host1x/dev.c#L475

Still I'm not a fan of the ad-hoc solution.

> Another solution is to defer probing of DP AUX driver while
> tegra_drm_device() returns NULL, but it's icky.
> 
> Reverting the original DP AUX DDC registration order is the best option
> so far, IMO.
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v1 2/2] drm/tegra: Use drm_dp_aux_register_ddc/chardev() helpers
  2021-11-09 14:39               ` Dmitry Osipenko
@ 2021-11-12 10:52                 ` Thierry Reding
  2021-11-12 14:32                   ` Dmitry Osipenko
  0 siblings, 1 reply; 13+ messages in thread
From: Thierry Reding @ 2021-11-12 10:52 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Jonathan Hunter, Lyude Paul, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Thomas Graichen, dri-devel,
	linux-tegra, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2050 bytes --]

On Tue, Nov 09, 2021 at 05:39:02PM +0300, Dmitry Osipenko wrote:
> 09.11.2021 17:17, Dmitry Osipenko пишет:
> > 09.11.2021 17:08, Dmitry Osipenko пишет:
> >>> +static void host1x_drm_dev_deinit(struct host1x_device *dev)
> >>> +{
> >>> +	struct drm_device *drm = dev_get_drvdata(&dev->dev);
> >> And platform_unregister_drivers() should be moved here.
> >>
> > 
> > Nah, that should cause deadlock. This ad-hoc is too lame.
> 
> Actually, there is no problem here as I see now. The host1x driver
> populates DT nodes after host1x_register() [1], meaning that Host1x DRM
> will be always inited first.
> 
> [1]
> https://elixir.bootlin.com/linux/v5.15/source/drivers/gpu/host1x/dev.c#L475
> 
> Still I'm not a fan of the ad-hoc solution.

Could we not fix this by making the panel "hot-pluggable"? I don't think
there's anything inherent to the driver that would prevent doing so. The
original reason for why things are as intertwined as they are now is
because back at the time deferred framebuffer creation didn't exist. In
fact I added deferred framebuffer support with Daniel's help precisely
to fix a similar issue for things like HDMI and DP.

With HDMI and DP it's slightly less critical, because a lack of mode
support would've created a 1024x768 framebuffer, which most HDMI/DP
monitors support. However, with panels we need to ensure that the exact
mode from the panel is used to create the framebuffer, so it can only be
created when the panel is available.

But, given that deferred framebuffer creation works now (which allows
the framebuffer console to show up at the preferred resolution for HDMI
and DP), even if a monitor is attached only after the driver has probed
already, we should be able to make something like that work with panels
as well.

Thierry

> > Another solution is to defer probing of DP AUX driver while
> > tegra_drm_device() returns NULL, but it's icky.
> > 
> > Reverting the original DP AUX DDC registration order is the best option
> > so far, IMO.
> > 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v1 2/2] drm/tegra: Use drm_dp_aux_register_ddc/chardev() helpers
  2021-11-12 10:52                 ` Thierry Reding
@ 2021-11-12 14:32                   ` Dmitry Osipenko
  2021-11-12 20:26                     ` Lyude Paul
  0 siblings, 1 reply; 13+ messages in thread
From: Dmitry Osipenko @ 2021-11-12 14:32 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Jonathan Hunter, Lyude Paul, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Thomas Graichen, dri-devel,
	linux-tegra, linux-kernel

12.11.2021 13:52, Thierry Reding пишет:
> On Tue, Nov 09, 2021 at 05:39:02PM +0300, Dmitry Osipenko wrote:
>> 09.11.2021 17:17, Dmitry Osipenko пишет:
>>> 09.11.2021 17:08, Dmitry Osipenko пишет:
>>>>> +static void host1x_drm_dev_deinit(struct host1x_device *dev)
>>>>> +{
>>>>> +	struct drm_device *drm = dev_get_drvdata(&dev->dev);
>>>> And platform_unregister_drivers() should be moved here.
>>>>
>>>
>>> Nah, that should cause deadlock. This ad-hoc is too lame.
>>
>> Actually, there is no problem here as I see now. The host1x driver
>> populates DT nodes after host1x_register() [1], meaning that Host1x DRM
>> will be always inited first.
>>
>> [1]
>> https://elixir.bootlin.com/linux/v5.15/source/drivers/gpu/host1x/dev.c#L475
>>
>> Still I'm not a fan of the ad-hoc solution.
> 
> Could we not fix this by making the panel "hot-pluggable"? I don't think
> there's anything inherent to the driver that would prevent doing so. The
> original reason for why things are as intertwined as they are now is
> because back at the time deferred framebuffer creation didn't exist. In
> fact I added deferred framebuffer support with Daniel's help precisely
> to fix a similar issue for things like HDMI and DP.

I don't understand what do you mean by "hot-pluggable", panel is static.
Please either clarify more or type the patch.

Keep in mind that fix should be simple and portable because stable
kernels are wrecked.

> With HDMI and DP it's slightly less critical, because a lack of mode
> support would've created a 1024x768 framebuffer, which most HDMI/DP
> monitors support. However, with panels we need to ensure that the exact
> mode from the panel is used to create the framebuffer, so it can only be
> created when the panel is available.
> 
> But, given that deferred framebuffer creation works now (which allows
> the framebuffer console to show up at the preferred resolution for HDMI
> and DP), even if a monitor is attached only after the driver has probed
> already, we should be able to make something like that work with panels
> as well.

BTW, I see now that DPAUX I2C transfer helper may access
aux->drm_device. Hence v1 patch isn't correct anyways.

For now I'll try to test more the ad-hoc variant with Thomas and send it
as v2 if we won't have a better solution.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v1 2/2] drm/tegra: Use drm_dp_aux_register_ddc/chardev() helpers
  2021-11-12 14:32                   ` Dmitry Osipenko
@ 2021-11-12 20:26                     ` Lyude Paul
  2021-11-12 20:45                       ` Dmitry Osipenko
  0 siblings, 1 reply; 13+ messages in thread
From: Lyude Paul @ 2021-11-12 20:26 UTC (permalink / raw)
  To: Dmitry Osipenko, Thierry Reding
  Cc: Jonathan Hunter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Thomas Graichen, dri-devel,
	linux-tegra, linux-kernel

On Fri, 2021-11-12 at 17:32 +0300, Dmitry Osipenko wrote:
> 12.11.2021 13:52, Thierry Reding пишет:
> > On Tue, Nov 09, 2021 at 05:39:02PM +0300, Dmitry Osipenko wrote:
> > > 09.11.2021 17:17, Dmitry Osipenko пишет:
> > > > 09.11.2021 17:08, Dmitry Osipenko пишет:
> > > > > > +static void host1x_drm_dev_deinit(struct host1x_device *dev)
> > > > > > +{
> > > > > > +       struct drm_device *drm = dev_get_drvdata(&dev->dev);
> > > > > And platform_unregister_drivers() should be moved here.
> > > > > 
> > > > 
> > > > Nah, that should cause deadlock. This ad-hoc is too lame.
> > > 
> > > Actually, there is no problem here as I see now. The host1x driver
> > > populates DT nodes after host1x_register() [1], meaning that Host1x DRM
> > > will be always inited first.
> > > 
> > > [1]
> > > https://elixir.bootlin.com/linux/v5.15/source/drivers/gpu/host1x/dev.c#L475
> > > 
> > > Still I'm not a fan of the ad-hoc solution.
> > 
> > Could we not fix this by making the panel "hot-pluggable"? I don't think
> > there's anything inherent to the driver that would prevent doing so. The
> > original reason for why things are as intertwined as they are now is
> > because back at the time deferred framebuffer creation didn't exist. In
> > fact I added deferred framebuffer support with Daniel's help precisely
> > to fix a similar issue for things like HDMI and DP.
> 
> I don't understand what do you mean by "hot-pluggable", panel is static.
> Please either clarify more or type the patch.
> 
> Keep in mind that fix should be simple and portable because stable
> kernels are wrecked.
> 
> > With HDMI and DP it's slightly less critical, because a lack of mode
> > support would've created a 1024x768 framebuffer, which most HDMI/DP
> > monitors support. However, with panels we need to ensure that the exact
> > mode from the panel is used to create the framebuffer, so it can only be
> > created when the panel is available.
> > 
> > But, given that deferred framebuffer creation works now (which allows
> > the framebuffer console to show up at the preferred resolution for HDMI
> > and DP), even if a monitor is attached only after the driver has probed
> > already, we should be able to make something like that work with panels
> > as well.
> 
> BTW, I see now that DPAUX I2C transfer helper may access
> aux->drm_device. Hence v1 patch isn't correct anyways.

JFYI - unless I'm misunderstanding you, the aux->drm_dev accesses in the DPAUX
i2c transfer functions are just from the various drm_{dbg,err,etc.} calls,
which means that they all should be able to handle aux->drm_dev being NULL. If
you can set aux->drm_dev before i2c transfers start that's more ideal, since
otherwise you'll see the AUX device name as "(null)" in the kernel log, but
any point before device registration should work.

> 
> For now I'll try to test more the ad-hoc variant with Thomas and send it
> as v2 if we won't have a better solution.
> 

-- 
Cheers,
 Lyude Paul (she/her)
 Software Engineer at Red Hat


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v1 2/2] drm/tegra: Use drm_dp_aux_register_ddc/chardev() helpers
  2021-11-12 20:26                     ` Lyude Paul
@ 2021-11-12 20:45                       ` Dmitry Osipenko
  0 siblings, 0 replies; 13+ messages in thread
From: Dmitry Osipenko @ 2021-11-12 20:45 UTC (permalink / raw)
  To: Lyude Paul, Thierry Reding
  Cc: Jonathan Hunter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Thomas Graichen, dri-devel,
	linux-tegra, linux-kernel

12.11.2021 23:26, Lyude Paul пишет:
>> BTW, I see now that DPAUX I2C transfer helper may access
>> aux->drm_device. Hence v1 patch isn't correct anyways.
> 
> JFYI - unless I'm misunderstanding you, the aux->drm_dev accesses in the DPAUX
> i2c transfer functions are just from the various drm_{dbg,err,etc.} calls,
> which means that they all should be able to handle aux->drm_dev being NULL. If
> you can set aux->drm_dev before i2c transfers start that's more ideal, since
> otherwise you'll see the AUX device name as "(null)" in the kernel log, but
> any point before device registration should work.

Thanks, I realized that have seen DRM log with a such debug messages
just a day ago.

drm drm: [drm:drm_dp_i2c_do_msg] (null): transaction timed out

So yes, it's indeed not critical.

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2021-11-12 20:45 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-07 23:08 [PATCH v1 1/2] drm/dp: Add drm_dp_aux_register_ddc/chardev() helpers Dmitry Osipenko
2021-11-07 23:08 ` [PATCH v1 2/2] drm/tegra: Use " Dmitry Osipenko
2021-11-08 15:17   ` Daniel Vetter
2021-11-08 18:16     ` Dmitry Osipenko
2021-11-09  9:19       ` Daniel Vetter
2021-11-09 13:52         ` Dmitry Osipenko
2021-11-09 14:08           ` Dmitry Osipenko
2021-11-09 14:17             ` Dmitry Osipenko
2021-11-09 14:39               ` Dmitry Osipenko
2021-11-12 10:52                 ` Thierry Reding
2021-11-12 14:32                   ` Dmitry Osipenko
2021-11-12 20:26                     ` Lyude Paul
2021-11-12 20:45                       ` Dmitry Osipenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).