[v3,01/22] drm: Include ddc adapter pointer in struct drm_connector
diff mbox series

Message ID d6381c020ea1c848a7044d830bdb0ec9663d1619.1561735433.git.andrzej.p@collabora.com
State New
Headers show
Series
  • Associate ddc adapters with connectors
Related show

Commit Message

Andrzej Pietrasiewicz June 28, 2019, 4:01 p.m. UTC
Add generic code which creates symbolic links in sysfs, pointing to ddc
interface used by a particular video output. For example:

ls -l /sys/class/drm/card0-HDMI-A-1/ddc
lrwxrwxrwx 1 root root 0 Jun 24 10:42 /sys/class/drm/card0-HDMI-A-1/ddc \
	-> ../../../../soc/13880000.i2c/i2c-2

This makes it easy for user to associate a display with its ddc adapter
and use e.g. ddcutil to control the chosen monitor.

This patch adds an i2c_adapter pointer to struct drm_connector. Particular
drivers can then use it instead of using their own private instance. If a
connector contains a ddc, then create a symbolic link in sysfs.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_sysfs.c |  7 +++++++
 include/drm/drm_connector.h | 11 +++++++++++
 2 files changed, 18 insertions(+)

Comments

Thomas Zimmermann June 30, 2019, 8:12 a.m. UTC | #1
Hi

I like the idea, but would prefer a more structured approach.

Setting connector->ddc before calling drm_sysfs_connector_add() seems
error prone. The dependency is not really clear from the code or interfaces.

The other thing is that drivers I mostly work on, ast and mgag200, have
code like this:

  struct ast_i2c_chan {
	struct i2c_adapter adapter;
	struct drm_device *dev;
	struct i2c_algo_bit_data bit;
  };

  struct ast_connector {
	struct drm_connector base;
	struct ast_i2c_chan *i2c;
  };

It already encodes the connection between connector and ddc adapter.

I suggest to introduce struct drm_i2c_adapter

  struct drm_i2c_adapter {
	struct i2c_adapter base;
	struct drm_connector *connector;
  };

and convert drivers over to it. Ast would look like this:

  struct ast_i2c_chan {
	struct drm_i2c_adapter adapter;
	struct i2c_algo_bit_data bit;
  };

Two new sysfs functions would set up and remove the file.

  int drm_sysfs_i2c_adapter_add(struct drm_i2c_adapter *i2c);
  void drm_sysfs_i2c_adapter_remove(struct drm_i2c_adapter *i2c);

The i2c adapter, connector->ddc pointer and sysfs entry would be
initialized by

  drm_i2c_adapter_init(struct drm_i2c_adapter *i2c, struct connector
	*connector, void *algo_data);

and cleaned up by

  drm_i2c_adapter_remove(struct drm_i2c_adapter *i2c);


Thoughts?

Best regards
Thomas

Am 28.06.19 um 18:01 schrieb Andrzej Pietrasiewicz:
> Add generic code which creates symbolic links in sysfs, pointing to ddc
> interface used by a particular video output. For example:
> 
> ls -l /sys/class/drm/card0-HDMI-A-1/ddc
> lrwxrwxrwx 1 root root 0 Jun 24 10:42 /sys/class/drm/card0-HDMI-A-1/ddc \
> 	-> ../../../../soc/13880000.i2c/i2c-2
> 
> This makes it easy for user to associate a display with its ddc adapter
> and use e.g. ddcutil to control the chosen monitor.
> 
> This patch adds an i2c_adapter pointer to struct drm_connector. Particular
> drivers can then use it instead of using their own private instance. If a
> connector contains a ddc, then create a symbolic link in sysfs.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/drm_sysfs.c |  7 +++++++
>  include/drm/drm_connector.h | 11 +++++++++++
>  2 files changed, 18 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
> index ad10810bc972..26d359b39785 100644
> --- a/drivers/gpu/drm/drm_sysfs.c
> +++ b/drivers/gpu/drm/drm_sysfs.c
> @@ -294,6 +294,9 @@ int drm_sysfs_connector_add(struct drm_connector *connector)
>  	/* Let userspace know we have a new connector */
>  	drm_sysfs_hotplug_event(dev);
>  
> +	if (connector->ddc)
> +		return sysfs_create_link(&connector->kdev->kobj,
> +				 &connector->ddc->dev.kobj, "ddc");
>  	return 0;
>  }
>  
> @@ -301,6 +304,10 @@ void drm_sysfs_connector_remove(struct drm_connector *connector)
>  {
>  	if (!connector->kdev)
>  		return;
> +
> +	if (connector->ddc)
> +		sysfs_remove_link(&connector->kdev->kobj, "ddc");
> +
>  	DRM_DEBUG("removing \"%s\" from sysfs\n",
>  		  connector->name);
>  
> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> index ca745d9feaf5..1ad3d1d54ba7 100644
> --- a/include/drm/drm_connector.h
> +++ b/include/drm/drm_connector.h
> @@ -23,6 +23,7 @@
>  #ifndef __DRM_CONNECTOR_H__
>  #define __DRM_CONNECTOR_H__
>  
> +#include <linux/i2c.h>
>  #include <linux/list.h>
>  #include <linux/llist.h>
>  #include <linux/ctype.h>
> @@ -1308,6 +1309,16 @@ struct drm_connector {
>  	 * [0]: progressive, [1]: interlaced
>  	 */
>  	int audio_latency[2];
> +
> +	/**
> +	 * @ddc: associated ddc adapter.
> +	 * A connector usually has its associated ddc adapter. If a driver uses
> +	 * this field, then an appropriate symbolic link is created in connector
> +	 * sysfs directory to make it easy for the user to tell which i2c
> +	 * adapter is for a particular display.
> +	 */
> +	struct i2c_adapter *ddc;
> +
>  	/**
>  	 * @null_edid_counter: track sinks that give us all zeros for the EDID.
>  	 * Needed to workaround some HW bugs where we get all 0s
>
Andrzej Pietrasiewicz July 1, 2019, 1:27 p.m. UTC | #2
Hi Thomas,

Thank you for your comments. Please see inline.

W dniu 30.06.2019 o 10:12, Thomas Zimmermann pisze:
> Hi
> 
> I like the idea, but would prefer a more structured approach.
> 
> Setting connector->ddc before calling drm_sysfs_connector_add() seems
> error prone. The dependency is not really clear from the code or interfaces.
> 
> The other thing is that drivers I mostly work on, ast and mgag200, have
> code like this:
> 
>    struct ast_i2c_chan {
> 	struct i2c_adapter adapter;
> 	struct drm_device *dev;
> 	struct i2c_algo_bit_data bit;
>    };
> 
>    struct ast_connector {
> 	struct drm_connector base;
> 	struct ast_i2c_chan *i2c;
>    };
> 
> It already encodes the connection between connector and ddc adapter.
> 
> I suggest to introduce struct drm_i2c_adapter
> 
>    struct drm_i2c_adapter {
> 	struct i2c_adapter base;
> 	struct drm_connector *connector;
>    };
> 
> and convert drivers over to it. Ast would look like this:
> 
>    struct ast_i2c_chan {
> 	struct drm_i2c_adapter adapter;
> 	struct i2c_algo_bit_data bit;
>    };
> 

There are few flavors of these drivers. In some of them
the i2c_adapter for ddc is allocated and initialized by
the driver, which must provide a place in memory to hold
the adapter. ast is an example of this approach.

But there are others, such as for example exynos_hdmi.c.
It gets its ddc adapter with of_find_i2c_adapter_by_node()
and merely stores a pointer to it, while not managing the
memory needed to hold the i2c_adapter.

Do you have any idea how to accommodate these various
flavors of drivers in the scheme you propose?

Andrzej
Thomas Zimmermann July 1, 2019, 2:41 p.m. UTC | #3
Hi

Am 01.07.19 um 15:27 schrieb Andrzej Pietrasiewicz:
> Hi Thomas,
> 
> Thank you for your comments. Please see inline.
> 
> W dniu 30.06.2019 o 10:12, Thomas Zimmermann pisze:
>> Hi
>>
>> I like the idea, but would prefer a more structured approach.
>>
>> Setting connector->ddc before calling drm_sysfs_connector_add() seems
>> error prone. The dependency is not really clear from the code or
>> interfaces.
>>
>> The other thing is that drivers I mostly work on, ast and mgag200, have
>> code like this:
>>
>>    struct ast_i2c_chan {
>>     struct i2c_adapter adapter;
>>     struct drm_device *dev;
>>     struct i2c_algo_bit_data bit;
>>    };
>>
>>    struct ast_connector {
>>     struct drm_connector base;
>>     struct ast_i2c_chan *i2c;
>>    };
>>
>> It already encodes the connection between connector and ddc adapter.
>>
>> I suggest to introduce struct drm_i2c_adapter
>>
>>    struct drm_i2c_adapter {
>>     struct i2c_adapter base;
>>     struct drm_connector *connector;
>>    };
>>
>> and convert drivers over to it. Ast would look like this:
>>
>>    struct ast_i2c_chan {
>>     struct drm_i2c_adapter adapter;
>>     struct i2c_algo_bit_data bit;
>>    };
>>
> 
> There are few flavors of these drivers. In some of them
> the i2c_adapter for ddc is allocated and initialized by
> the driver, which must provide a place in memory to hold
> the adapter. ast is an example of this approach.
> 
> But there are others, such as for example exynos_hdmi.c.
> It gets its ddc adapter with of_find_i2c_adapter_by_node()
> and merely stores a pointer to it, while not managing the
> memory needed to hold the i2c_adapter.

I see.

> Do you have any idea how to accommodate these various
> flavors of drivers in the scheme you propose?

Something like

  struct drm_i2c_adapter {
	struct i2c_adapter *adapter;
	struct drm_connector *connector;
  };

with adapter either being allocated dynamically or acquired via
of_find_i2c_adapter_by_node(); with separate init and finish functions
for each variant. But it looks like over-abstraction to me. Without
prototyping the idea, I cannot say if it's worth the effort.

For something more simple, maybe just have a function to attach an i2c
adapter to a connector:

  drm_connector_attach_i2c_adapter(connector, i2c_adapter)

which sets the connector's ddc pointer and creates the sysfs entry if
the connector's entry is already present.

Best regards
Thomas

> Andrzej
> 
>
Andrzej Hajda July 5, 2019, 9:44 a.m. UTC | #4
On 01.07.2019 16:41, Thomas Zimmermann wrote:
> Hi
>
> Am 01.07.19 um 15:27 schrieb Andrzej Pietrasiewicz:
>> Hi Thomas,
>>
>> Thank you for your comments. Please see inline.
>>
>> W dniu 30.06.2019 o 10:12, Thomas Zimmermann pisze:
>>> Hi
>>>
>>> I like the idea, but would prefer a more structured approach.
>>>
>>> Setting connector->ddc before calling drm_sysfs_connector_add() seems
>>> error prone. The dependency is not really clear from the code or
>>> interfaces.
>>>
>>> The other thing is that drivers I mostly work on, ast and mgag200, have
>>> code like this:
>>>
>>>    struct ast_i2c_chan {
>>>     struct i2c_adapter adapter;
>>>     struct drm_device *dev;
>>>     struct i2c_algo_bit_data bit;
>>>    };
>>>
>>>    struct ast_connector {
>>>     struct drm_connector base;
>>>     struct ast_i2c_chan *i2c;
>>>    };
>>>
>>> It already encodes the connection between connector and ddc adapter.
>>>
>>> I suggest to introduce struct drm_i2c_adapter
>>>
>>>    struct drm_i2c_adapter {
>>>     struct i2c_adapter base;
>>>     struct drm_connector *connector;
>>>    };
>>>
>>> and convert drivers over to it. Ast would look like this:
>>>
>>>    struct ast_i2c_chan {
>>>     struct drm_i2c_adapter adapter;
>>>     struct i2c_algo_bit_data bit;
>>>    };
>>>
>> There are few flavors of these drivers. In some of them
>> the i2c_adapter for ddc is allocated and initialized by
>> the driver, which must provide a place in memory to hold
>> the adapter. ast is an example of this approach.
>>
>> But there are others, such as for example exynos_hdmi.c.
>> It gets its ddc adapter with of_find_i2c_adapter_by_node()
>> and merely stores a pointer to it, while not managing the
>> memory needed to hold the i2c_adapter.
> I see.
>
>> Do you have any idea how to accommodate these various
>> flavors of drivers in the scheme you propose?
> Something like
>
>   struct drm_i2c_adapter {
> 	struct i2c_adapter *adapter;
> 	struct drm_connector *connector;
>   };
>
> with adapter either being allocated dynamically or acquired via
> of_find_i2c_adapter_by_node(); with separate init and finish functions
> for each variant. But it looks like over-abstraction to me. Without
> prototyping the idea, I cannot say if it's worth the effort.
>
> For something more simple, maybe just have a function to attach an i2c
> adapter to a connector:
>
>   drm_connector_attach_i2c_adapter(connector, i2c_adapter)
>
> which sets the connector's ddc pointer and creates the sysfs entry if
> the connector's entry is already present.


I am not sure if such function is really necessary. Assigning ddc field
before connector registration seems to be much simpler and quite
standard - many fields are initialized this way.


Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>

 --
Regards
Andrzej



> Best regards
> Thomas
>
>> Andrzej
>>
>>

Patch
diff mbox series

diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index ad10810bc972..26d359b39785 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -294,6 +294,9 @@  int drm_sysfs_connector_add(struct drm_connector *connector)
 	/* Let userspace know we have a new connector */
 	drm_sysfs_hotplug_event(dev);
 
+	if (connector->ddc)
+		return sysfs_create_link(&connector->kdev->kobj,
+				 &connector->ddc->dev.kobj, "ddc");
 	return 0;
 }
 
@@ -301,6 +304,10 @@  void drm_sysfs_connector_remove(struct drm_connector *connector)
 {
 	if (!connector->kdev)
 		return;
+
+	if (connector->ddc)
+		sysfs_remove_link(&connector->kdev->kobj, "ddc");
+
 	DRM_DEBUG("removing \"%s\" from sysfs\n",
 		  connector->name);
 
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index ca745d9feaf5..1ad3d1d54ba7 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -23,6 +23,7 @@ 
 #ifndef __DRM_CONNECTOR_H__
 #define __DRM_CONNECTOR_H__
 
+#include <linux/i2c.h>
 #include <linux/list.h>
 #include <linux/llist.h>
 #include <linux/ctype.h>
@@ -1308,6 +1309,16 @@  struct drm_connector {
 	 * [0]: progressive, [1]: interlaced
 	 */
 	int audio_latency[2];
+
+	/**
+	 * @ddc: associated ddc adapter.
+	 * A connector usually has its associated ddc adapter. If a driver uses
+	 * this field, then an appropriate symbolic link is created in connector
+	 * sysfs directory to make it easy for the user to tell which i2c
+	 * adapter is for a particular display.
+	 */
+	struct i2c_adapter *ddc;
+
 	/**
 	 * @null_edid_counter: track sinks that give us all zeros for the EDID.
 	 * Needed to workaround some HW bugs where we get all 0s