Skip to contentSkip to conversation

drm/vc4: Avoid using vrefresh==0 mode in DSI htotal math.

PATCH In review Eric Anholt 7 participants 25 messages Jul 18, 2017 – Aug 9, 2017

Subsystems (7)
lore
Share & tools
lore
#0 lore raw

PATCH v5 1/6 drm/vc4: Avoid using vrefresh==0 mode in DSI htotal math.

The incoming mode might have a missing vrefresh field if it came from drmModeSetCrtc(), which the kernel is supposed to calculate using drm_mode_vrefresh(). We could either use that or the adjusted_mode's original vrefresh value.

However, we can maintain a more exact vrefresh value (not just the integer approximation), by scaling by the ratio of our clocks.

v2: Use math suggested by Andrzej Hajda instead.

---
 drivers/gpu/drm/vc4/vc4_dsi.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/vc4/vc4_dsi.c +2 -1
index 629d372633e6..57213f4e3c72 100644
@@ -866,7 +866,8 @@ static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
 	adjusted_mode->clock = pixel_clock_hz / 1000 + 1;
 
 	/* Given the new pixel clock, adjust HFP to keep vrefresh the same. */
-	adjusted_mode->htotal = pixel_clock_hz / (mode->vrefresh * mode->vtotal);
+	adjusted_mode->htotal = (pixel_clock_hz / 1000 * mode->htotal /
+				 mode->clock);
 	adjusted_mode->hsync_end += adjusted_mode->htotal - mode->htotal;
 	adjusted_mode->hsync_start += adjusted_mode->htotal - mode->htotal;
 
Signature · 6 lines
2.11.0

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#1 lore raw

PATCH v5 2/6 drm/bridge: Add a devm_ allocator for panel bridge.

This will let drivers reduce the error cleanup they need, in particular the "is_panel_bridge" flag.

v2: Slight cleanup of remove function by Andrzej

---
 drivers/gpu/drm/bridge/panel.c | 30 ++++++++++++++++++++++++++++++
 include/drm/drm_bridge.h       |  3 +++
 2 files changed, 33 insertions(+)
drivers/gpu/drm/bridge/panel.c +30 -0
index 685c1a480201..292ee92a9c97 100644
@@ -195,3 +195,33 @@ void drm_panel_bridge_remove(struct drm_bridge *bridge)
 	devm_kfree(panel_bridge->panel->dev, bridge);
 }
 EXPORT_SYMBOL(drm_panel_bridge_remove);
+
+static void devm_drm_panel_bridge_release(struct device *dev, void *res)
+{
+	struct drm_bridge **bridge = res;
+
+	drm_panel_bridge_remove(*bridge);
+}
+
+struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
+					     struct drm_panel *panel,
+					     u32 connector_type)
+{
+	struct drm_bridge **ptr, *bridge;
+
+	ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr),
+			   GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	bridge = drm_panel_bridge_add(panel, connector_type);
+	if (!IS_ERR(bridge)) {
+		*ptr = bridge;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return bridge;
+}
+EXPORT_SYMBOL(devm_drm_panel_bridge_add);
include/drm/drm_bridge.h +3 -0
index 1dc94d5392e2..6522d4cbc9d9 100644
@@ -268,6 +268,9 @@ void drm_bridge_enable(struct drm_bridge *bridge);
 struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel,
 					u32 connector_type);
 void drm_panel_bridge_remove(struct drm_bridge *bridge);
+struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
+					     struct drm_panel *panel,
+					     u32 connector_type);
 #endif
 
 #endif
Signature · 6 lines
2.11.0

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Reviewed-by Tested-by on v5 2/6
#2 lore raw

Re: [PATCH v5 2/6] drm/bridge: Add a devm_ allocator for panel bridge.

Quoted 7 lines · Eric Anholt

This will let drivers reduce the error cleanup they need, in particular the "is_panel_bridge" flag.

v2: Slight cleanup of remove function by Andrzej

Quoted 49 lines
---
  drivers/gpu/drm/bridge/panel.c | 30 ++++++++++++++++++++++++++++++
  include/drm/drm_bridge.h       |  3 +++
  2 files changed, 33 insertions(+)
drivers/gpu/drm/bridge/panel.c +30 -0
index 685c1a480201..292ee92a9c97 100644
@@ -195,3 +195,33 @@ void drm_panel_bridge_remove(struct drm_bridge *bridge)
  	devm_kfree(panel_bridge->panel->dev, bridge);
  }
  EXPORT_SYMBOL(drm_panel_bridge_remove);
+
+static void devm_drm_panel_bridge_release(struct device *dev, void *res)
+{
+	struct drm_bridge **bridge = res;
+
+	drm_panel_bridge_remove(*bridge);
+}
+
+struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
+					     struct drm_panel *panel,
+					     u32 connector_type)
+{
+	struct drm_bridge **ptr, *bridge;
+
+	ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr),
+			   GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	bridge = drm_panel_bridge_add(panel, connector_type);
+	if (!IS_ERR(bridge)) {
+		*ptr = bridge;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return bridge;
+}
+EXPORT_SYMBOL(devm_drm_panel_bridge_add);
include/drm/drm_bridge.h +0 -0
index 1dc94d5392e2..6522d4cbc9d9 100644

include/drm/drm_bridge.h void drm_bridge_enable(struct drm_bridge *bridge); · line 276

Quoted 9 lines
include/drm/drm_bridge.h +3 -0
@@ -268,6 +268,9 @@ void drm_bridge_enable(struct drm_bridge *bridge);
  struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel,
  					u32 connector_type);
  void drm_panel_bridge_remove(struct drm_bridge *bridge);
+struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
+					     struct drm_panel *panel,
+					     u32 connector_type);
  #endif
 
  #endif

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#3 lore raw

Re: [PATCH v5 2/6] drm/bridge: Add a devm_ allocator for panel bridge.

Quoted 11 lines · Philippe CORNU
Quoted 7 lines · Eric Anholt

This will let drivers reduce the error cleanup they need, in particular the "is_panel_bridge" flag.

v2: Slight cleanup of remove function by Andrzej

I've pushed this patch from the series, but hopefully I can get some review on the rest.

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#4 lore raw

Re: [PATCH v5 2/6] drm/bridge: Add a devm_ allocator for panel bridge.

In reply to Eric Anholt

Hi Eric,

(CC'ing Daniel)

Thank you for the patch.

Quoted 4 lines · On Tuesday 18 Jul 2017 14:05:06 Eric Anholt wrote:

This will let drivers reduce the error cleanup they need, in particular the "is_panel_bridge" flag.

v2: Slight cleanup of remove function by Andrzej

I just want to point out that, in the context of Daniel's work on hot-unplug, 90% of the devm_* allocations are wrong and will get in the way. All DRM core objects that are accessible one way or another from userspace will need to be properly reference-counted and freed only when the last reference disappears, which could be well after the corresponding device is removed. I believe this could be one such objects :-/

Quoted 59 lines
---
 drivers/gpu/drm/bridge/panel.c | 30 ++++++++++++++++++++++++++++++
 include/drm/drm_bridge.h       |  3 +++
 2 files changed, 33 insertions(+)
drivers/gpu/drm/bridge/panel.c +30 -0
index 685c1a480201..292ee92a9c97 100644
@@ -195,3 +195,33 @@ void drm_panel_bridge_remove(struct drm_bridge *bridge)
 devm_kfree(panel_bridge->panel->dev, bridge);
 }
 EXPORT_SYMBOL(drm_panel_bridge_remove);
+
+static void devm_drm_panel_bridge_release(struct device *dev, void *res)
+{
+	struct drm_bridge **bridge = res;
+
+	drm_panel_bridge_remove(*bridge);
+}
+
+struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
+					     struct drm_panel *panel,
+					     u32 connector_type)
+{
+	struct drm_bridge **ptr, *bridge;
+
+	ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr),
+			   GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	bridge = drm_panel_bridge_add(panel, connector_type);
+	if (!IS_ERR(bridge)) {
+		*ptr = bridge;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return bridge;
+}
+EXPORT_SYMBOL(devm_drm_panel_bridge_add);
include/drm/drm_bridge.h +3 -0
index 1dc94d5392e2..6522d4cbc9d9 100644
@@ -268,6 +268,9 @@ void drm_bridge_enable(struct drm_bridge *bridge);
 struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel,
 					u32 connector_type);
 void drm_panel_bridge_remove(struct drm_bridge *bridge);
+struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
+					     struct drm_panel *panel,
+					     u32 connector_type);
 #endif
 
 #endif
Signature · 3 lines
Regards,

Laurent Pinchart
#5 lore raw

Re: [PATCH v5 2/6] drm/bridge: Add a devm_ allocator for panel bridge.

Now CC'ing Daniel with his correct address :-/ I'll blame auto-completion in my e-mail client. Sorry for the noise.

Quoted 86 lines · On Friday 04 Aug 2017 16:46:24 Laurent Pinchart wrote:

Hi Eric,

(CC'ing Daniel)

Thank you for the patch.

Quoted 4 lines · On Tuesday 18 Jul 2017 14:05:06 Eric Anholt wrote:

This will let drivers reduce the error cleanup they need, in particular the "is_panel_bridge" flag.

v2: Slight cleanup of remove function by Andrzej

I just want to point out that, in the context of Daniel's work on hot-unplug, 90% of the devm_* allocations are wrong and will get in the way. All DRM core objects that are accessible one way or another from userspace will need to be properly reference-counted and freed only when the last reference disappears, which could be well after the corresponding device is removed. I believe this could be one such objects :-/

Quoted 67 lines

---

 drivers/gpu/drm/bridge/panel.c | 30 ++++++++++++++++++++++++++++++
 include/drm/drm_bridge.h       |  3 +++
 2 files changed, 33 insertions(+)
(quoted diff) +0 -0

b/drivers/gpu/drm/bridge/panel.c index 685c1a480201..292ee92a9c97 100644

drivers/gpu/drm/bridge/panel.c +30 -0
@@ -195,3 +195,33 @@ void drm_panel_bridge_remove(struct drm_bridge
 *bridge) devm_kfree(panel_bridge->panel->dev, bridge);
 
 }
 EXPORT_SYMBOL(drm_panel_bridge_remove);
 
+
+static void devm_drm_panel_bridge_release(struct device *dev, void *res)
+{
+	struct drm_bridge **bridge = res;
+
+	drm_panel_bridge_remove(*bridge);
+}
+
+struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
+					     struct drm_panel *panel,
+					     u32 connector_type)
+{
+	struct drm_bridge **ptr, *bridge;
+
+	ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr),
+			   GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	bridge = drm_panel_bridge_add(panel, connector_type);
+	if (!IS_ERR(bridge)) {
+		*ptr = bridge;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return bridge;
+}
+EXPORT_SYMBOL(devm_drm_panel_bridge_add);
include/drm/drm_bridge.h +3 -0
index 1dc94d5392e2..6522d4cbc9d9 100644
@@ -268,6 +268,9 @@ void drm_bridge_enable(struct drm_bridge *bridge);
 
 struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel,
 
 					u32 connector_type);
 
 void drm_panel_bridge_remove(struct drm_bridge *bridge);
 
+struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
+					     struct drm_panel *panel,
+					     u32 connector_type);
 
 #endif
 
 #endif
Signature · 3 lines
Regards,

Laurent Pinchart
#6 lore raw

Re: [PATCH v5 2/6] drm/bridge: Add a devm_ allocator for panel bridge.

In reply to Laurent Pinchart
Quoted 10 lines · Laurent Pinchart

Hi Eric,

(CC'ing Daniel)

Thank you for the patch.

Quoted 3 lines · On Tuesday 18 Jul 2017 14:05:06 Eric Anholt wrote:

This will let drivers reduce the error cleanup they need, in particular the "is_panel_bridge" flag.

Quoted 8 lines
Quoted 1 line

v2: Slight cleanup of remove function by Andrzej

I just want to point out that, in the context of Daniel's work on hot-unplug, 90% of the devm_* allocations are wrong and will get in the way. All DRM core objects that are accessible one way or another from userspace will need to be properly reference-counted and freed only when the last reference disappears, which could be well after the corresponding device is removed. I believe this could be one such objects :-/

Sure, if you're hotplugging, your life is pain. For non-hotpluggable devices, like our SOC platform devices (current panel-bridge consumers), this still seems like an excellent simplification of memory management.

#7 lore raw

Re: [PATCH v5 2/6] drm/bridge: Add a devm_ allocator for panel bridge.

Hi Eric,

Quoted 15 lines · On Friday 04 Aug 2017 13:43:25 Eric Anholt wrote:
Quoted 6 lines · Laurent Pinchart
Quoted 4 lines · On Tuesday 18 Jul 2017 14:05:06 Eric Anholt wrote:

This will let drivers reduce the error cleanup they need, in particular the "is_panel_bridge" flag.

v2: Slight cleanup of remove function by Andrzej

Quoted 7 lines

I just want to point out that, in the context of Daniel's work on hot-unplug, 90% of the devm_* allocations are wrong and will get in the way. All DRM core objects that are accessible one way or another from userspace will need to be properly reference-counted and freed only when the last reference disappears, which could be well after the corresponding device is removed. I believe this could be one such objects :-/

Quoted 3 lines

Sure, if you're hotplugging, your life is pain. For non-hotpluggable devices, like our SOC platform devices (current panel-bridge consumers), this still seems like an excellent simplification of memory management.

It encourages driver writers to write code that they will have to fix later. That's certainly a simplification, but certainly not a good thing in my opinion :-)

Signature · 3 lines
Regards,

Laurent Pinchart
#8 lore raw

Re: [PATCH v5 2/6] drm/bridge: Add a devm_ allocator for panel bridge.

In reply to Eric Anholt
Quoted 21 lines · Eric Anholt
Quoted 10 lines · Laurent Pinchart

Hi Eric,

(CC'ing Daniel)

Thank you for the patch.

Quoted 3 lines · On Tuesday 18 Jul 2017 14:05:06 Eric Anholt wrote:

This will let drivers reduce the error cleanup they need, in particular the "is_panel_bridge" flag.

Quoted 8 lines
Quoted 1 line

v2: Slight cleanup of remove function by Andrzej

I just want to point out that, in the context of Daniel's work on hot-unplug, 90% of the devm_* allocations are wrong and will get in the way. All DRM core objects that are accessible one way or another from userspace will need to be properly reference-counted and freed only when the last reference disappears, which could be well after the corresponding device is removed. I believe this could be one such objects :-/

Quoted 3 lines

Sure, if you're hotplugging, your life is pain. For non-hotpluggable devices, like our SOC platform devices (current panel-bridge consumers), this still seems like an excellent simplification of memory management.

At that point you may as well make your module non-unloadable, and return failure when trying to remove a device from management by the driver (whatever the opposite of "probe" is, I forget). Hotplugging doesn't only happen when physically removing, it can happen for all kinds of reasons... and userspace may still hold references in some of those cases.
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#9 lore raw

Re: [PATCH v5 2/6] drm/bridge: Add a devm_ allocator for panel bridge.

(I had to switch to Daniel's Intel address to get this sent)

Den 05.08.2017 00.19, skrev Ilia Mirkin:

Quoted 23 lines · Eric Anholt
Quoted 19 lines
Quoted 10 lines · Laurent Pinchart

Hi Eric,

(CC'ing Daniel)

Thank you for the patch.

Quoted 3 lines · On Tuesday 18 Jul 2017 14:05:06 Eric Anholt wrote:

This will let drivers reduce the error cleanup they need, in particular the "is_panel_bridge" flag.

Quoted 7 lines
Quoted 1 line

v2: Slight cleanup of remove function by Andrzej

I just want to point out that, in the context of Daniel's work on hot-unplug, 90% of the devm_* allocations are wrong and will get in the way. All DRM core objects that are accessible one way or another from userspace will need to be properly reference-counted and freed only when the last reference disappears, which could be well after the corresponding device is removed. I believe this could be one such objects :-/

Quoted 3 lines

Sure, if you're hotplugging, your life is pain. For non-hotpluggable devices, like our SOC platform devices (current panel-bridge consumers), this still seems like an excellent simplification of memory management.

Quoted 6 lines

At that point you may as well make your module non-unloadable, and return failure when trying to remove a device from management by the driver (whatever the opposite of "probe" is, I forget). Hotplugging doesn't only happen when physically removing, it can happen for all kinds of reasons... and userspace may still hold references in some of those cases.

If drm_open() gets a ref on dev->dev and puts it in drm_release(), won't that delay devm_* cleanup until userspace is done?

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#10 lore raw

Re: [PATCH v5 2/6] drm/bridge: Add a devm_ allocator for panel bridge.

Den 05.08.2017 12.59, skrev Noralf Trønnes:

Quoted 33 lines

(I had to switch to Daniel's Intel address to get this sent)

Den 05.08.2017 00.19, skrev Ilia Mirkin:

Quoted 23 lines · Eric Anholt
Quoted 19 lines
Quoted 10 lines · Laurent Pinchart

Hi Eric,

(CC'ing Daniel)

Thank you for the patch.

Quoted 3 lines · On Tuesday 18 Jul 2017 14:05:06 Eric Anholt wrote:

This will let drivers reduce the error cleanup they need, in particular the "is_panel_bridge" flag.

Quoted 7 lines
Quoted 1 line

v2: Slight cleanup of remove function by Andrzej

I just want to point out that, in the context of Daniel's work on hot-unplug, 90% of the devm_* allocations are wrong and will get in the way. All DRM core objects that are accessible one way or another from userspace will need to be properly reference-counted and freed only when the last reference disappears, which could be well after the corresponding device is removed. I believe this could be one such objects :-/

Quoted 3 lines

Sure, if you're hotplugging, your life is pain. For non-hotpluggable devices, like our SOC platform devices (current panel-bridge consumers), this still seems like an excellent simplification of memory management.

Quoted 6 lines

At that point you may as well make your module non-unloadable, and return failure when trying to remove a device from management by the driver (whatever the opposite of "probe" is, I forget). Hotplugging doesn't only happen when physically removing, it can happen for all kinds of reasons... and userspace may still hold references in some of those cases.

Quoted 3 lines

If drm_open() gets a ref on dev->dev and puts it in drm_release(), won't that delay devm_* cleanup until userspace is done?

It seems plausible looking at the code:

void device_initialize(struct device *dev)
{
[...]

    kobject_init(&dev->kobj, &device_ktype);

[...]
}

static struct kobj_type device_ktype = {
.release = device_release,
};

/**
* device_release - free device structure.
* @kobj: device's kobject.
*
* This is called once the reference count for the object
* reaches 0. We forward the call to the device's release
* method, which should handle actually freeing the structure. */
static void device_release(struct kobject *kobj)
{
[...]

    devres_release_all(dev);

[...]
}

Last put call chain:
put_device() -> kobject_put() -> kref_put() -> kobject_release() -> kobject_cleanup() -> device_release() -> devres_release_all()

But I haven't actually tried it, so I might be mistaken.

#11 lore raw

Re: [PATCH v5 2/6] drm/bridge: Add a devm_ allocator for panel bridge.

In reply to Noralf Trønnes
Quoted 33 lines · Noralf Trønnes

(I had to switch to Daniel's Intel address to get this sent)

Den 05.08.2017 00.19, skrev Ilia Mirkin:

Quoted 23 lines · Eric Anholt
Quoted 19 lines
Quoted 10 lines · Laurent Pinchart

Hi Eric,

(CC'ing Daniel)

Thank you for the patch.

Quoted 3 lines · On Tuesday 18 Jul 2017 14:05:06 Eric Anholt wrote:

This will let drivers reduce the error cleanup they need, in particular the "is_panel_bridge" flag.

Quoted 7 lines
Quoted 1 line

v2: Slight cleanup of remove function by Andrzej

I just want to point out that, in the context of Daniel's work on hot-unplug, 90% of the devm_* allocations are wrong and will get in the way. All DRM core objects that are accessible one way or another from userspace will need to be properly reference-counted and freed only when the last reference disappears, which could be well after the corresponding device is removed. I believe this could be one such objects :-/

Quoted 3 lines

Sure, if you're hotplugging, your life is pain. For non-hotpluggable devices, like our SOC platform devices (current panel-bridge consumers), this still seems like an excellent simplification of memory management.

Quoted 6 lines

At that point you may as well make your module non-unloadable, and return failure when trying to remove a device from management by the driver (whatever the opposite of "probe" is, I forget). Hotplugging doesn't only happen when physically removing, it can happen for all kinds of reasons... and userspace may still hold references in some of those cases.

Quoted 2 lines

If drm_open() gets a ref on dev->dev and puts it in drm_release(), won't that delay devm_* cleanup until userspace is done?

No. drm_device is the thing that is refcounted for userspace references like open FD (we're not perfect about it, e.g. sysfs and dma-buf/fence don't).

devm_ otoh is tied to the lifetime of the underlying device, and that one can get outlived by drm_device. Or at least afaiui, devm_ stuff is nuked on unplug, and not when the final sw reference of the struct device disappears.

Not sure tough, it's complicated.
-Daniel

Signature · 7 lines
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#12 lore raw

Re: [PATCH v5 2/6] drm/bridge: Add a devm_ allocator for panel bridge.

Hi Daniel,

Quoted 37 lines · On Monday 07 Aug 2017 11:25:07 Daniel Vetter wrote:
Quoted 29 lines · Noralf Trønnes

Den 05.08.2017 00.19, skrev Ilia Mirkin:

Quoted 21 lines · Eric Anholt
Quoted 15 lines
Quoted 6 lines · Laurent Pinchart
Quoted 4 lines · On Tuesday 18 Jul 2017 14:05:06 Eric Anholt wrote:

This will let drivers reduce the error cleanup they need, in particular the "is_panel_bridge" flag.

v2: Slight cleanup of remove function by Andrzej

Quoted 7 lines

I just want to point out that, in the context of Daniel's work on hot-unplug, 90% of the devm_* allocations are wrong and will get in the way. All DRM core objects that are accessible one way or another from userspace will need to be properly reference-counted and freed only when the last reference disappears, which could be well after the corresponding device is removed. I believe this could be one such objects :-/

Quoted 4 lines

Sure, if you're hotplugging, your life is pain. For non-hotpluggable devices, like our SOC platform devices (current panel-bridge consumers), this still seems like an excellent simplification of memory management.

Quoted 6 lines

At that point you may as well make your module non-unloadable, and return failure when trying to remove a device from management by the driver (whatever the opposite of "probe" is, I forget). Hotplugging doesn't only happen when physically removing, it can happen for all kinds of reasons... and userspace may still hold references in some of those cases.

Quoted 2 lines

If drm_open() gets a ref on dev->dev and puts it in drm_release(), won't that delay devm_* cleanup until userspace is done?

No. drm_device is the thing that is refcounted for userspace references like open FD (we're not perfect about it, e.g. sysfs and dma-buf/fence don't).

Quoted 6 lines

devm_ otoh is tied to the lifetime of the underlying device, and that one can get outlived by drm_device. Or at least afaiui, devm_ stuff is nuked on unplug, and not when the final sw reference of the struct device disappears.

Not sure tough, it's complicated.

It's complicated when you have to understand the behaviour by reading the code, but the behaviour isn't that complex. devm resources are released both

1. right after the driver's .remove() operation returns
2. when the device is deleted (last reference released)

It's the first one that makes devm_* allocation unsuitable for any structure that is accessible from userspace (such as in file operation handlers).

Signature · 8 lines
Regards,

Laurent Pinchart

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#13 lore raw

Re: [PATCH v5 2/6] drm/bridge: Add a devm_ allocator for panel bridge.

Den 07.08.2017 12.22, skrev Laurent Pinchart:

Quoted 41 lines

Hi Daniel,

Quoted 32 lines · On Monday 07 Aug 2017 11:25:07 Daniel Vetter wrote:
Quoted 19 lines · Noralf Trønnes

Den 05.08.2017 00.19, skrev Ilia Mirkin:

Quoted 18 lines · Eric Anholt
Quoted 17 lines
Quoted 4 lines · Laurent Pinchart
Quoted 3 lines · On Tuesday 18 Jul 2017 14:05:06 Eric Anholt wrote:

This will let drivers reduce the error cleanup they need, in particular the "is_panel_bridge" flag.

Quoted 8 lines
Quoted 1 line

v2: Slight cleanup of remove function by Andrzej

I just want to point out that, in the context of Daniel's work on hot-unplug, 90% of the devm_* allocations are wrong and will get in the way. All DRM core objects that are accessible one way or another from userspace will need to be properly reference-counted and freed only when the last reference disappears, which could be well after the corresponding device is removed. I believe this could be one such objects :-/

Sure, if you're hotplugging, your life is pain. For non-hotpluggable devices, like our SOC platform devices (current panel-bridge consumers), this still seems like an excellent simplification of memory management.

Quoted 8 lines
Quoted 6 lines

At that point you may as well make your module non-unloadable, and return failure when trying to remove a device from management by the driver (whatever the opposite of "probe" is, I forget). Hotplugging doesn't only happen when physically removing, it can happen for all kinds of reasons... and userspace may still hold references in some of those cases.

If drm_open() gets a ref on dev->dev and puts it in drm_release(), won't that delay devm_* cleanup until userspace is done?

No. drm_device is the thing that is refcounted for userspace references like open FD (we're not perfect about it, e.g. sysfs and dma-buf/fence don't).

Quoted 6 lines

devm_ otoh is tied to the lifetime of the underlying device, and that one can get outlived by drm_device. Or at least afaiui, devm_ stuff is nuked on unplug, and not when the final sw reference of the struct device disappears.

Not sure tough, it's complicated.

Quoted 9 lines

It's complicated when you have to understand the behaviour by reading the code, but the behaviour isn't that complex. devm resources are released both

1. right after the driver's .remove() operation returns
2. when the device is deleted (last reference released)

It's the first one that makes devm_* allocation unsuitable for any structure that is accessible from userspace (such as in file operation handlers).

I see, when the device is removed, the driver is released. No help holding a ref on struct device.
I did a test and this is the stack trace in devm_tinydrm_release():

[  129.433179] [<c0016148>] (unwind_backtrace) from [<c0013c90>] (show_stack+0x20/0x24)
[  129.433213] [<c0013c90>] (show_stack) from [<c0319e78>] (dump_stack+0x20/0x28)
[  129.433242] [<c0319e78>] (dump_stack) from [<c0021d18>] (__warn+0xe4/0x10c)
[  129.433264] [<c0021d18>] (__warn) from [<c0021e0c>] (warn_slowpath_null+0x30/0x38)
[  129.433324] [<c0021e0c>] (warn_slowpath_null) from [<bf2ca3cc>] (devm_tinydrm_release+0x24/0x48 [tinydrm])
[  129.433389] [<bf2ca3cc>] (devm_tinydrm_release [tinydrm]) from [<c03bf7f0>] (devm_action_release+0x1c/0x20)
[  129.433414] [<c03bf7f0>] (devm_action_release) from [<c03bfc70>] (release_nodes+0x188/0x21c)
[  129.433437] [<c03bfc70>] (release_nodes) from [<c03c076c>] (devres_release_all+0x44/0x64)
[  129.433461] [<c03c076c>] (devres_release_all) from [<c03bcdb8>] (__device_release_driver+0x9c/0x118)
[  129.433480] [<c03bcdb8>] (__device_release_driver) from [<c03bce60>] (device_release_driver+0x2c/0x38)
[  129.433499] [<c03bce60>] (device_release_driver) from [<c03bbe04>] (bus_remove_device+0xe4/0x114)
[  129.433532] [<c03bbe04>] (bus_remove_device) from [<c03b8980>] (device_del+0x118/0x22c)
[  129.433554] [<c03b8980>] (device_del) from [<c03b8ab0>] (device_unregister+0x1c/0x30)
[  129.433592] [<c03b8ab0>] (device_unregister) from [<c04062c0>] (spi_unregister_device+0x60/0x64)
[  129.433617] [<c04062c0>] (spi_unregister_device) from [<c0409438>] (of_spi_notify+0x70/0x164)
[  129.433642] [<c0409438>] (of_spi_notify) from [<c0040148>] (notifier_call_chain+0x54/0x94)
[  129.433664] [<c0040148>] (notifier_call_chain) from [<c00405dc>] (__blocking_notifier_call_chain+0x58/0x70)
[  129.433683] [<c00405dc>] (__blocking_notifier_call_chain) from [<c004061c>] (blocking_notifier_call_chain+0x28/0x30)
[  129.433721] [<c004061c>] (blocking_notifier_call_chain) from [<c04b7058>] (__of_changeset_entry_notify+0x90/0xe0)
[  129.433748] [<c04b7058>] (__of_changeset_entry_notify) from [<c04b7aec>] (__of_changeset_revert+0x70/0xcc)
[  129.433774] [<c04b7aec>] (__of_changeset_revert) from [<c04bb46c>] (of_overlay_destroy+0x10c/0x1bc)
[  129.433795] [<c04bb46c>] (of_overlay_destroy) from [<c04b6954>] (cfs_overlay_release+0x2c/0x50)
[  129.433832] [<c04b6954>] (cfs_overlay_release) from [<c01be83c>] (config_item_release+0x68/0x8c)
[  129.433859] [<c01be83c>] (config_item_release) from [<c01be7d0>] (config_item_put+0x44/0x48)
[  129.433879] [<c01be7d0>] (config_item_put) from [<c01bcf50>] (configfs_rmdir+0x190/0x220)
[  129.433902] [<c01bcf50>] (configfs_rmdir) from [<c0152204>] (vfs_rmdir+0x80/0x118)
[  129.433922] [<c0152204>] (vfs_rmdir) from [<c01547f8>] (do_rmdir+0x144/0x1a0)
[  129.433941] [<c01547f8>] (do_rmdir) from [<c01551f0>] (SyS_rmdir+0x20/0x24)
[  129.433966] [<c01551f0>] (SyS_rmdir) from [<c000fe40>] (ret_fast_syscall+0x0/0x1c)

This means that tinydrm won't work with usb devices. I need to look into moving cleanup to drm_driver->cleanup.

Noralf.

#14 lore raw

Re: [PATCH v5 2/6] drm/bridge: Add a devm_ allocator for panel bridge.

In reply to Laurent Pinchart
Quoted 45 lines · Laurent Pinchart

Hi Daniel,

Quoted 42 lines · On Monday 07 Aug 2017 11:25:07 Daniel Vetter wrote:
Quoted 29 lines · Noralf Trønnes

Den 05.08.2017 00.19, skrev Ilia Mirkin:

Quoted 21 lines · Eric Anholt
Quoted 15 lines
Quoted 6 lines · Laurent Pinchart
Quoted 4 lines · On Tuesday 18 Jul 2017 14:05:06 Eric Anholt wrote:

This will let drivers reduce the error cleanup they need, in particular the "is_panel_bridge" flag.

v2: Slight cleanup of remove function by Andrzej

Quoted 7 lines

I just want to point out that, in the context of Daniel's work on hot-unplug, 90% of the devm_* allocations are wrong and will get in the way. All DRM core objects that are accessible one way or another from userspace will need to be properly reference-counted and freed only when the last reference disappears, which could be well after the corresponding device is removed. I believe this could be one such objects :-/

Quoted 4 lines

Sure, if you're hotplugging, your life is pain. For non-hotpluggable devices, like our SOC platform devices (current panel-bridge consumers), this still seems like an excellent simplification of memory management.

Quoted 6 lines

At that point you may as well make your module non-unloadable, and return failure when trying to remove a device from management by the driver (whatever the opposite of "probe" is, I forget). Hotplugging doesn't only happen when physically removing, it can happen for all kinds of reasons... and userspace may still hold references in some of those cases.

Quoted 2 lines

If drm_open() gets a ref on dev->dev and puts it in drm_release(), won't that delay devm_* cleanup until userspace is done?

No. drm_device is the thing that is refcounted for userspace references like open FD (we're not perfect about it, e.g. sysfs and dma-buf/fence don't).

devm_ otoh is tied to the lifetime of the underlying device, and that one can get outlived by drm_device. Or at least afaiui, devm_ stuff is nuked on unplug, and not when the final sw reference of the struct device disappears.

Quoted 7 lines
Quoted 1 line

Not sure tough, it's complicated.

It's complicated when you have to understand the behaviour by reading the code, but the behaviour isn't that complex. devm resources are released both

1. right after the driver's .remove() operation returns
2. when the device is deleted (last reference released)

Right, I had vague memories when reading the code ... But iirc there's also some way to delay cleanup until it's deleted, maybe we could exploit that (and wrap it up into a drm_devm_add wrapper)?

Plan B, but that is a lot more ugly, would be to create a fake struct device that we never bind (hence remove can't be called) and use to track the lifetime of drm_device stuff. Would avoid re-inventing all the devm_ functions, but would also result in a dummy device in sysfs.

Why is this stuff tied to struct device and not struct kobject anyway. Or at least something we could embed in random cool place (like drm_device).

Greg, any ideas how we could simplify management of stuff that's created at driver load, but its lifetime tied to something which isn't directly a struct device?

Quoted 2 lines

It's the first one that makes devm_* allocation unsuitable for any structure that is accessible from userspace (such as in file operation handlers).

Yeah, if we could release at 2. it would be perfect I think ... -Daniel

Signature · 7 lines
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#15 lore raw

Re: [PATCH v5 2/6] drm/bridge: Add a devm_ allocator for panel bridge.

Hi Daniel,

Quoted 53 lines · On Monday 07 Aug 2017 16:59:39 Daniel Vetter wrote:
Quoted 43 lines · Laurent Pinchart
Quoted 42 lines · On Monday 07 Aug 2017 11:25:07 Daniel Vetter wrote:
Quoted 29 lines · Noralf Trønnes

Den 05.08.2017 00.19, skrev Ilia Mirkin:

Quoted 21 lines · Eric Anholt
Quoted 15 lines
Quoted 6 lines · Laurent Pinchart
Quoted 4 lines · On Tuesday 18 Jul 2017 14:05:06 Eric Anholt wrote:

This will let drivers reduce the error cleanup they need, in particular the "is_panel_bridge" flag.

v2: Slight cleanup of remove function by Andrzej

Quoted 7 lines

I just want to point out that, in the context of Daniel's work on hot-unplug, 90% of the devm_* allocations are wrong and will get in the way. All DRM core objects that are accessible one way or another from userspace will need to be properly reference-counted and freed only when the last reference disappears, which could be well after the corresponding device is removed. I believe this could be one such objects :-/

Quoted 4 lines

Sure, if you're hotplugging, your life is pain. For non-hotpluggable devices, like our SOC platform devices (current panel-bridge consumers), this still seems like an excellent simplification of memory management.

Quoted 6 lines

At that point you may as well make your module non-unloadable, and return failure when trying to remove a device from management by the driver (whatever the opposite of "probe" is, I forget). Hotplugging doesn't only happen when physically removing, it can happen for all kinds of reasons... and userspace may still hold references in some of those cases.

Quoted 2 lines

If drm_open() gets a ref on dev->dev and puts it in drm_release(), won't that delay devm_* cleanup until userspace is done?

No. drm_device is the thing that is refcounted for userspace references like open FD (we're not perfect about it, e.g. sysfs and dma-buf/fence don't).

devm_ otoh is tied to the lifetime of the underlying device, and that one can get outlived by drm_device. Or at least afaiui, devm_ stuff is nuked on unplug, and not when the final sw reference of the struct device disappears.

Quoted 8 lines
Quoted 1 line

Not sure tough, it's complicated.

It's complicated when you have to understand the behaviour by reading the code, but the behaviour isn't that complex. devm resources are released both

1. right after the driver's .remove() operation returns
2. when the device is deleted (last reference released)

Quoted 8 lines

Right, I had vague memories when reading the code ... But iirc there's also some way to delay cleanup until it's deleted, maybe we could exploit that (and wrap it up into a drm_devm_add wrapper)?

Plan B, but that is a lot more ugly, would be to create a fake struct device that we never bind (hence remove can't be called) and use to track the lifetime of drm_device stuff. Would avoid re-inventing all the devm_ functions, but would also result in a dummy device in sysfs.

If we wanted to go that way, we should decouple devm_* from struct device (or even struct kobject) and tie it to a new resource tracker structure. The current devm_* API would remain the same, embedding that resource tracker object in struct device, but we could also use the machinery with the resource tracker object directly.

However, I'm not convince we should do so. We don't have any automatic memory allocation system for DRM objects (such as framebuffers or planes). Instead, drivers must implement a destroy operation for the object, and the core calls it when the last reference to the object goes away. This works fine, and I don't see what would prevent use from implementing the same mechanism for bridges or other similar structures.

Quoted 7 lines

Why is this stuff tied to struct device and not struct kobject anyway. Or at least something we could embed in random cool place (like drm_device).

Greg, any ideas how we could simplify management of stuff that's created at driver load, but its lifetime tied to something which isn't directly a struct device?

Quoted 5 lines
Quoted 3 lines

It's the first one that makes devm_* allocation unsuitable for any structure that is accessible from userspace (such as in file operation handlers).

Yeah, if we could release at 2. it would be perfect I think ...

It wouldn't, as unbind/rebind cycles would allocate new objects each time without freeing the previous ones until the device is deleted.

Signature · 8 lines
Regards,

Laurent Pinchart

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#16 lore raw

PATCH v5 3/6 drm/vc4: Delay DSI host registration until the panel has probed.

In reply to Eric Anholt

The vc4 driver was unusual in that it was delaying the panel lookup until the attach step, while most DSI hosts will -EPROBE_DEFER until they get a panel.

v2: Drop a debug message that slipped in.

---
 drivers/gpu/drm/vc4/vc4_dsi.c | 38 ++++++++++++++------------------------
 1 file changed, 14 insertions(+), 24 deletions(-)
drivers/gpu/drm/vc4/vc4_dsi.c +14 -24
index 57213f4e3c72..769f247c52a9 100644
@@ -33,6 +33,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
 #include <drm/drm_panel.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
@@ -504,7 +505,6 @@ struct vc4_dsi {
 	struct mipi_dsi_host dsi_host;
 	struct drm_encoder *encoder;
 	struct drm_bridge *bridge;
-	bool is_panel_bridge;
 
 	void __iomem *regs;
 
@@ -1289,7 +1289,6 @@ static int vc4_dsi_host_attach(struct mipi_dsi_host *host,
 			       struct mipi_dsi_device *device)
 {
 	struct vc4_dsi *dsi = host_to_dsi(host);
-	int ret = 0;
 
 	dsi->lanes = device->lanes;
 	dsi->channel = device->channel;
@@ -1324,34 +1323,12 @@ static int vc4_dsi_host_attach(struct mipi_dsi_host *host,
 		return 0;
 	}
 
-	dsi->bridge = of_drm_find_bridge(device->dev.of_node);
-	if (!dsi->bridge) {
-		struct drm_panel *panel =
-			of_drm_find_panel(device->dev.of_node);
-
-		dsi->bridge = drm_panel_bridge_add(panel,
-						   DRM_MODE_CONNECTOR_DSI);
-		if (IS_ERR(dsi->bridge)) {
-			ret = PTR_ERR(dsi->bridge);
-			dsi->bridge = NULL;
-			return ret;
-		}
-		dsi->is_panel_bridge = true;
-	}
-
 	return drm_bridge_attach(dsi->encoder, dsi->bridge, NULL);
 }
 
 static int vc4_dsi_host_detach(struct mipi_dsi_host *host,
 			       struct mipi_dsi_device *device)
 {
-	struct vc4_dsi *dsi = host_to_dsi(host);
-
-	if (dsi->is_panel_bridge) {
-		drm_panel_bridge_remove(dsi->bridge);
-		dsi->bridge = NULL;
-	}
-
 	return 0;
 }
 
@@ -1495,6 +1472,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
 	struct vc4_dev *vc4 = to_vc4_dev(drm);
 	struct vc4_dsi *dsi;
 	struct vc4_dsi_encoder *vc4_dsi_encoder;
+	struct drm_panel *panel;
 	const struct of_device_id *match;
 	dma_cap_mask_t dma_mask;
 	int ret;
@@ -1598,6 +1576,18 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
 		return ret;
 	}
 
+	ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
+					  &panel, &dsi->bridge);
+	if (ret)
+		return ret;
+
+	if (panel) {
+		dsi->bridge = devm_drm_panel_bridge_add(dev, panel,
+							DRM_MODE_CONNECTOR_DSI);
+		if (IS_ERR(dsi->bridge))
+			return PTR_ERR(dsi->bridge);
+	}
+
 	/* The esc clock rate is supposed to always be 100Mhz. */
 	ret = clk_set_rate(dsi->escape_clock, 100 * 1000000);
 	if (ret) {
Signature · 6 lines
2.11.0

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Reviewed-by on v5 3/6
#17 lore raw

Re: [PATCH v5 3/6] drm/vc4: Delay DSI host registration until the panel has probed.

Quoted 8 lines · On Tue, 18 Jul 2017 14:05:07 -0700 Eric Anholt <[email protected]> wrote:

The vc4 driver was unusual in that it was delaying the panel lookup until the attach step, while most DSI hosts will -EPROBE_DEFER until they get a panel.

v2: Drop a debug message that slipped in.

Quoted 94 lines
---
 drivers/gpu/drm/vc4/vc4_dsi.c | 38 ++++++++++++++------------------------
 1 file changed, 14 insertions(+), 24 deletions(-)
drivers/gpu/drm/vc4/vc4_dsi.c +14 -24
index 57213f4e3c72..769f247c52a9 100644
@@ -33,6 +33,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
 #include <drm/drm_panel.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
@@ -504,7 +505,6 @@ struct vc4_dsi {
 	struct mipi_dsi_host dsi_host;
 	struct drm_encoder *encoder;
 	struct drm_bridge *bridge;
-	bool is_panel_bridge;
 
 	void __iomem *regs;
 
@@ -1289,7 +1289,6 @@ static int vc4_dsi_host_attach(struct mipi_dsi_host *host,
 			       struct mipi_dsi_device *device)
 {
 	struct vc4_dsi *dsi = host_to_dsi(host);
-	int ret = 0;
 
 	dsi->lanes = device->lanes;
 	dsi->channel = device->channel;
@@ -1324,34 +1323,12 @@ static int vc4_dsi_host_attach(struct mipi_dsi_host *host,
 		return 0;
 	}
 
-	dsi->bridge = of_drm_find_bridge(device->dev.of_node);
-	if (!dsi->bridge) {
-		struct drm_panel *panel =
-			of_drm_find_panel(device->dev.of_node);
-
-		dsi->bridge = drm_panel_bridge_add(panel,
-						   DRM_MODE_CONNECTOR_DSI);
-		if (IS_ERR(dsi->bridge)) {
-			ret = PTR_ERR(dsi->bridge);
-			dsi->bridge = NULL;
-			return ret;
-		}
-		dsi->is_panel_bridge = true;
-	}
-
 	return drm_bridge_attach(dsi->encoder, dsi->bridge, NULL);
 }
 
 static int vc4_dsi_host_detach(struct mipi_dsi_host *host,
 			       struct mipi_dsi_device *device)
 {
-	struct vc4_dsi *dsi = host_to_dsi(host);
-
-	if (dsi->is_panel_bridge) {
-		drm_panel_bridge_remove(dsi->bridge);
-		dsi->bridge = NULL;
-	}
-
 	return 0;
 }
 
@@ -1495,6 +1472,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
 	struct vc4_dev *vc4 = to_vc4_dev(drm);
 	struct vc4_dsi *dsi;
 	struct vc4_dsi_encoder *vc4_dsi_encoder;
+	struct drm_panel *panel;
 	const struct of_device_id *match;
 	dma_cap_mask_t dma_mask;
 	int ret;
@@ -1598,6 +1576,18 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
 		return ret;
 	}
 
+	ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
+					  &panel, &dsi->bridge);
+	if (ret)
+		return ret;
+
+	if (panel) {
+		dsi->bridge = devm_drm_panel_bridge_add(dev, panel,
+							DRM_MODE_CONNECTOR_DSI);
+		if (IS_ERR(dsi->bridge))
+			return PTR_ERR(dsi->bridge);
+	}
+
 	/* The esc clock rate is supposed to always be 100Mhz. */
 	ret = clk_set_rate(dsi->escape_clock, 100 * 1000000);
 	if (ret) {
#18 lore raw

PATCH v5 4/6 drm: Allow DSI devices to be registered before the host registers.

In reply to Eric Anholt

When a mipi_dsi_host is registered, the DT is walked to find any child nodes with compatible strings. Those get registered as DSI devices, and most DSI panel drivers are mipi_dsi_drivers that attach to those nodes.

There is one special case currently, the adv7533 bridge, where the bridge probes on I2C, and during the bridge attach step it looks up the mipi_dsi_host and registers the mipi_dsi_device (for its own stub mipi_dsi_driver).

For the Raspberry Pi panel, though, we also need to attach on I2C (our control bus), but don't have a bridge driver. The lack of a bridge's attach() step like adv7533 uses means that we aren't able to delay the mipi_dsi_device creation until the mipi_dsi_host is present.

To fix this, we extend mipi_dsi_device_register_full() to allow being called with a NULL host, which puts the device on a queue waiting for a host to appear. When a new host is registered, we fill in the host value and finish the device creation process.

v2: Cleanly error out if one attempts to mipi_dsi_attach() without a
host. Fix handling of DSI with multiple devices, and OF node refcounting.

---
 drivers/gpu/drm/drm_mipi_dsi.c | 63 ++++++++++++++++++++++++++++++++++--------
 include/drm/drm_mipi_dsi.h     |  3 ++
 2 files changed, 54 insertions(+), 12 deletions(-)
drivers/gpu/drm/drm_mipi_dsi.c +51 -12
index 1160a579e0dc..77d439254da6 100644
@@ -45,6 +45,13 @@
  * subset of the MIPI DCS command set.
  */
 
+static DEFINE_MUTEX(host_lock);
+static LIST_HEAD(host_list);
+/* List of struct mipi_dsi_device which were registered while no host
+ * was available.
+ */
+static LIST_HEAD(unattached_device_list);
+
 static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv)
 {
 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
@@ -138,10 +145,12 @@ static struct mipi_dsi_device *mipi_dsi_device_alloc(struct mipi_dsi_host *host)
 
 	dsi->host = host;
 	dsi->dev.bus = &mipi_dsi_bus_type;
-	dsi->dev.parent = host->dev;
 	dsi->dev.type = &mipi_dsi_device_type;
 
-	device_initialize(&dsi->dev);
+	if (dsi->host) {
+		dsi->dev.parent = host->dev;
+		device_initialize(&dsi->dev);
+	}
 
 	return dsi;
 }
@@ -206,7 +215,7 @@ mipi_dsi_device_register_full(struct mipi_dsi_host *host,
 			      const struct mipi_dsi_device_info *info)
 {
 	struct mipi_dsi_device *dsi;
-	struct device *dev = host->dev;
+	struct device *dev = host ? host->dev : NULL;
 	int ret;
 
 	if (!info) {
@@ -230,11 +239,17 @@ mipi_dsi_device_register_full(struct mipi_dsi_host *host,
 	dsi->channel = info->channel;
 	strlcpy(dsi->name, info->type, sizeof(dsi->name));
 
-	ret = mipi_dsi_device_add(dsi);
-	if (ret) {
-		dev_err(dev, "failed to add DSI device %d\n", ret);
-		kfree(dsi);
-		return ERR_PTR(ret);
+	if (!dsi->host) {
+		mutex_lock(&host_lock);
+		list_add(&dsi->list, &unattached_device_list);
+		mutex_unlock(&host_lock);
+	} else {
+		ret = mipi_dsi_device_add(dsi);
+		if (ret) {
+			dev_err(dev, "failed to add DSI device %d\n", ret);
+			kfree(dsi);
+			return ERR_PTR(ret);
+		}
 	}
 
 	return dsi;
@@ -251,9 +266,6 @@ void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi)
 }
 EXPORT_SYMBOL(mipi_dsi_device_unregister);
 
-static DEFINE_MUTEX(host_lock);
-static LIST_HEAD(host_list);
-
 /**
  * of_find_mipi_dsi_host_by_node() - find the MIPI DSI host matching a
  *				     device tree node
@@ -285,6 +297,7 @@ EXPORT_SYMBOL(of_find_mipi_dsi_host_by_node);
 int mipi_dsi_host_register(struct mipi_dsi_host *host)
 {
 	struct device_node *node;
+	struct mipi_dsi_device *dsi, *temp;
 
 	for_each_available_child_of_node(host->dev->of_node, node) {
 		/* skip nodes without reg property */
@@ -295,6 +308,27 @@ int mipi_dsi_host_register(struct mipi_dsi_host *host)
 
 	mutex_lock(&host_lock);
 	list_add_tail(&host->list, &host_list);
+
+	/* If any DSI devices were registered under our OF node, then
+	 * connect our host to it and probe them now.
+	 */
+	list_for_each_entry_safe(dsi, temp, &unattached_device_list, list) {
+		struct device_node *host_node = of_get_parent(dsi->dev.of_node);
+
+		if (!of_node_cmp(host_node->name, "ports"))
+			host_node = of_get_next_parent(host_node);
+
+		if (host_node == host->dev->of_node) {
+			dsi->host = host;
+			dsi->dev.parent = host->dev;
+			device_initialize(&dsi->dev);
+
+			mipi_dsi_device_add(dsi);
+			list_del_init(&dsi->list);
+		}
+
+		of_node_put(host_node);
+	}
 	mutex_unlock(&host_lock);
 
 	return 0;
@@ -326,7 +360,12 @@ EXPORT_SYMBOL(mipi_dsi_host_unregister);
  */
 int mipi_dsi_attach(struct mipi_dsi_device *dsi)
 {
-	const struct mipi_dsi_host_ops *ops = dsi->host->ops;
+	const struct mipi_dsi_host_ops *ops;
+
+	if (!dsi->host)
+		return -EINVAL;
+
+	ops = dsi->host->ops;
 
 	if (!ops || !ops->attach)
 		return -ENOSYS;
include/drm/drm_mipi_dsi.h +3 -0
index 4fef19064b0f..dfe640fec9ba 100644
@@ -168,6 +168,7 @@ struct mipi_dsi_device_info {
  * @format: pixel format for video mode
  * @lanes: number of active data lanes
  * @mode_flags: DSI operation mode related flags
+ * @list: Entry on the unattached_device_list
  */
 struct mipi_dsi_device {
 	struct mipi_dsi_host *host;
@@ -178,6 +179,8 @@ struct mipi_dsi_device {
 	unsigned int lanes;
 	enum mipi_dsi_pixel_format format;
 	unsigned long mode_flags;
+
+	struct list_head list;
 };
 
 #define MIPI_DSI_MODULE_PREFIX "mipi-dsi:"
Signature · 6 lines
2.11.0

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#19 lore raw

Re: [PATCH v5 4/6] drm: Allow DSI devices to be registered before the host registers.

Quoted 49 lines · Eric Anholt

When a mipi_dsi_host is registered, the DT is walked to find any child nodes with compatible strings. Those get registered as DSI devices, and most DSI panel drivers are mipi_dsi_drivers that attach to those nodes.

There is one special case currently, the adv7533 bridge, where the bridge probes on I2C, and during the bridge attach step it looks up the mipi_dsi_host and registers the mipi_dsi_device (for its own stub mipi_dsi_driver).

For the Raspberry Pi panel, though, we also need to attach on I2C (our control bus), but don't have a bridge driver. The lack of a bridge's attach() step like adv7533 uses means that we aren't able to delay the mipi_dsi_device creation until the mipi_dsi_host is present.

To fix this, we extend mipi_dsi_device_register_full() to allow being called with a NULL host, which puts the device on a queue waiting for a host to appear. When a new host is registered, we fill in the host value and finish the device creation process.

v2: Cleanly error out if one attempts to mipi_dsi_attach() without a
host. Fix handling of DSI with multiple devices, and OF node refcounting.

---
 drivers/gpu/drm/drm_mipi_dsi.c | 63 ++++++++++++++++++++++++++++++++++--------
 include/drm/drm_mipi_dsi.h     |  3 ++
 2 files changed, 54 insertions(+), 12 deletions(-)
drivers/gpu/drm/drm_mipi_dsi.c +11 -0
index 1160a579e0dc..77d439254da6 100644
@@ -295,6 +308,27 @@ int mipi_dsi_host_register(struct mipi_dsi_host *host)
 
 	mutex_lock(&host_lock);
 	list_add_tail(&host->list, &host_list);
+
+	/* If any DSI devices were registered under our OF node, then
+	 * connect our host to it and probe them now.
+	 */
+	list_for_each_entry_safe(dsi, temp, &unattached_device_list, list) {
+		struct device_node *host_node = of_get_parent(dsi->dev.of_node);
+
+		if (!of_node_cmp(host_node->name, "ports"))
+			host_node = of_get_next_parent(host_node);
+
+		if (host_node == host->dev->of_node) {

drivers/gpu/drm/drm_mipi_dsi.c int mipi_dsi_host_register(struct mipi_dsi_host *host) · line 331

Quoted 10 lines
drivers/gpu/drm/drm_mipi_dsi.c +10 -0
+			dsi->host = host;
+			dsi->dev.parent = host->dev;
+			device_initialize(&dsi->dev);
+
+			mipi_dsi_device_add(dsi);
+			list_del_init(&dsi->list);
+		}
+
+		of_node_put(host_node);
+	}

Kbuild test caught that of_get_next_parent() isn't defined for !CONFIG_OF, so I've put this loop under IS_ENABLED(CONFIG_OF) for v3.

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#20 lore raw

PATCH v5 5/6 dt-bindings: Document the Raspberry Pi Touchscreen nodes.

In reply to Eric Anholt

This doesn't yet cover input, but the driver does get the display working when the firmware is disabled from talking to our I2C lines.

---
 .../panel/raspberrypi,7inch-touchscreen.txt        | 49 ++++++++++++++++++++++
 1 file changed, 49 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/raspberrypi,7inch-touchscreen.txt
Documentation/devicetree/bindings/display/panel/raspberrypi,7inch-touchscreen.txt new file +49 -0
new file mode 100644
index 000000000000..e9e19c059260
@@ -0,0 +1,49 @@
+This binding covers the official 7" (800x480) Raspberry Pi touchscreen
+panel.
+
+This DSI panel contains:
+
+- TC358762 DSI->DPI bridge
+- Atmel microcontroller on I2C for power sequencing the DSI bridge and
+  controlling backlight
+- Touchscreen controller on I2C for touch input
+
+and this binding covers the DSI display parts but not its touch input.
+
+Required properties:
+- compatible:	Must be "raspberrypi,7inch-touchscreen-panel"
+- reg:		Must be "45"
+- port:		See panel-common.txt
+
+Example:
+
+dsi1: dsi@7e700000 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	<...>
+
+	port {
+		dsi_out_port: endpoint {
+			remote-endpoint = <&panel_dsi_port>;
+		};
+	};
+};
+
+i2c_dsi: i2c {
+	compatible = "i2c-gpio";
+	#address-cells = <1>;
+	#size-cells = <0>;
+	gpios = <&gpio 28 0
+		 &gpio 29 0>;
+
+	lcd@45 {
+		compatible = "raspberrypi,7inch-touchscreen-panel";
+		reg = <0x45>;
+
+		port {
+			panel_dsi_port: endpoint {
+				remote-endpoint = <&dsi_out_port>;
+			};
+		};
+	};
+};
Signature · 6 lines
2.11.0

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#21 lore raw

PATCH v5 6/6 drm/panel: Add support for the Raspberry Pi 7" Touchscreen.

In reply to Eric Anholt

This driver communicates with the Atmel microcontroller for sequencing the poweron of the TC358762 DSI-DPI bridge and controlling the backlight PWM.

v2: Set the same default orientation as the closed source firmware
used, which is the best for viewing angle.
v3: Rewrite as an i2c client driver after bridge driver rejection.
v4: Finish probe without the DSI host, using the new delayed
registration, and attach to the host during mipi_dsi_driver probe.

---
 drivers/gpu/drm/panel/Kconfig                      |   8 +
 drivers/gpu/drm/panel/Makefile                     |   1 +
 .../gpu/drm/panel/panel-raspberrypi-touchscreen.c  | 505 +++++++++++++++++++++
 3 files changed, 514 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
drivers/gpu/drm/panel/Kconfig +8 -0
index d84a031fae24..d6f1969b8a3b 100644
@@ -73,6 +73,14 @@ config DRM_PANEL_PANASONIC_VVX10F034N00
 	  WUXGA (1920x1200) Novatek NT1397-based DSI panel as found in some
 	  Xperia Z2 tablets
 
+config DRM_PANEL_RASPBERRYPI_TOUCHSCREEN
+	tristate "Raspberry Pi 7-inch touchscreen panel"
+	depends on DRM_MIPI_DSI
+	help
+	  Say Y here if you want to enable support for the Raspberry
+	  Pi 7" Touchscreen.  To compile this driver as a module,
+	  choose M here.
+
 config DRM_PANEL_SAMSUNG_S6E3HA2
 	tristate "Samsung S6E3HA2 DSI video mode panel"
 	depends on OF
drivers/gpu/drm/panel/Makefile +1 -0
index 9f6610d08b00..bd17fac21c7b 100644
@@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o
 obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o
 obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
 obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o
+obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c new file +505 -0

505 lines not on this page · raw message

Signature · 6 lines
2.11.0

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#22 lore raw
In reply to Eric Anholt
Quoted 20 lines · On Tue, 18 Jul 2017 14:05:05 -0700 Eric Anholt <[email protected]> wrote:

The incoming mode might have a missing vrefresh field if it came from drmModeSetCrtc(), which the kernel is supposed to calculate using drm_mode_vrefresh(). We could either use that or the adjusted_mode's original vrefresh value.

However, we can maintain a more exact vrefresh value (not just the integer approximation), by scaling by the ratio of our clocks.

v2: Use math suggested by Andrzej Hajda instead.

---
 drivers/gpu/drm/vc4/vc4_dsi.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/vc4/vc4_dsi.c +0 -0
index 629d372633e6..57213f4e3c72 100644

drivers/gpu/drm/vc4/vc4_dsi.c static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder, · line 870

Quoted 6 lines
drivers/gpu/drm/vc4/vc4_dsi.c +2 -1
@@ -866,7 +866,8 @@ static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
 	adjusted_mode->clock = pixel_clock_hz / 1000 + 1;
 
 	/* Given the new pixel clock, adjust HFP to keep vrefresh the same. */
-	adjusted_mode->htotal = pixel_clock_hz / (mode->vrefresh * mode->vtotal);
+	adjusted_mode->htotal = (pixel_clock_hz / 1000 * mode->htotal /
+				 mode->clock);

Hm, I'm not sure I understand this. Shouldn't we have something like:

	adjusted_mode->htotal = (adjusted_mode->clock * mode->htotal) /
				mode->clock;

Is there a reason for doing '+ 1' when you calculate the adjusted pixel clock rate but not here?

Quoted 3 lines
drivers/gpu/drm/vc4/vc4_dsi.c +0 -0
 	adjusted_mode->hsync_end += adjusted_mode->htotal - mode->htotal;
 	adjusted_mode->hsync_start += adjusted_mode->htotal - mode->htotal;
 
#23 lore raw
Quoted 32 lines · Boris Brezillon
Quoted 20 lines · On Tue, 18 Jul 2017 14:05:05 -0700 Eric Anholt <[email protected]> wrote:

The incoming mode might have a missing vrefresh field if it came from drmModeSetCrtc(), which the kernel is supposed to calculate using drm_mode_vrefresh(). We could either use that or the adjusted_mode's original vrefresh value.

However, we can maintain a more exact vrefresh value (not just the integer approximation), by scaling by the ratio of our clocks.

v2: Use math suggested by Andrzej Hajda instead.

---
 drivers/gpu/drm/vc4/vc4_dsi.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/vc4/vc4_dsi.c +0 -0
index 629d372633e6..57213f4e3c72 100644

drivers/gpu/drm/vc4/vc4_dsi.c static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder, · line 870

Quoted 6 lines
drivers/gpu/drm/vc4/vc4_dsi.c +2 -1
@@ -866,7 +866,8 @@ static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
 	adjusted_mode->clock = pixel_clock_hz / 1000 + 1;
 
 	/* Given the new pixel clock, adjust HFP to keep vrefresh the same. */
-	adjusted_mode->htotal = pixel_clock_hz / (mode->vrefresh * mode->vtotal);
+	adjusted_mode->htotal = (pixel_clock_hz / 1000 * mode->htotal /
+				 mode->clock);

Hm, I'm not sure I understand this. Shouldn't we have something like:

Quoted 5 lines
	adjusted_mode->htotal = (adjusted_mode->clock * mode->htotal) /
				mode->clock;

Is there a reason for doing '+ 1' when you calculate the adjusted pixel clock rate but not here?

We're actually expecting to get within epsilon of pixel_clock_hz, but we have to bump our clk_set_rate() to a higher value because the clock driver will give you a bad divider if you ask for anything less than the rate it can provide.

How about I don't increment the adjusted_mode->clock (since it'll be userspace visible I think), and instead move that and the "Round up" comment to the clk_set_rate()?

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#24 lore raw
Quoted 40 lines · Eric Anholt
Quoted 32 lines · Boris Brezillon
Quoted 20 lines · On Tue, 18 Jul 2017 14:05:05 -0700 Eric Anholt <[email protected]> wrote:

The incoming mode might have a missing vrefresh field if it came from drmModeSetCrtc(), which the kernel is supposed to calculate using drm_mode_vrefresh(). We could either use that or the adjusted_mode's original vrefresh value.

However, we can maintain a more exact vrefresh value (not just the integer approximation), by scaling by the ratio of our clocks.

v2: Use math suggested by Andrzej Hajda instead.

---
 drivers/gpu/drm/vc4/vc4_dsi.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/vc4/vc4_dsi.c +0 -0
index 629d372633e6..57213f4e3c72 100644

drivers/gpu/drm/vc4/vc4_dsi.c static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder, · line 870

Quoted 6 lines
drivers/gpu/drm/vc4/vc4_dsi.c +2 -1
@@ -866,7 +866,8 @@ static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
 	adjusted_mode->clock = pixel_clock_hz / 1000 + 1;
 
 	/* Given the new pixel clock, adjust HFP to keep vrefresh the same. */
-	adjusted_mode->htotal = pixel_clock_hz / (mode->vrefresh * mode->vtotal);
+	adjusted_mode->htotal = (pixel_clock_hz / 1000 * mode->htotal /
+				 mode->clock);  

Hm, I'm not sure I understand this. Shouldn't we have something like:

Quoted 5 lines
	adjusted_mode->htotal = (adjusted_mode->clock * mode->htotal) /
				mode->clock;

Is there a reason for doing '+ 1' when you calculate the adjusted pixel clock rate but not here?

Quoted 8 lines

We're actually expecting to get within epsilon of pixel_clock_hz, but we have to bump our clk_set_rate() to a higher value because the clock driver will give you a bad divider if you ask for anything less than the rate it can provide.

How about I don't increment the adjusted_mode->clock (since it'll be userspace visible I think), and instead move that and the "Round up" comment to the clk_set_rate()?

Sounds good.
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel