We are currently restricted when it comes to supporting DSI on devices that have a non-DSI control bus. For example, DSI encoder chips are available in the market that are configured via i2c. Configuring their registers via DSI bus is either optional or not available at all.
These devices still need to pass DSI parameters (data lanes, mode flags etc) to the DSI host they are connected to. We don't have a way to do that at the moment.
The method presented in these patches is to provide an API to create a 'dummy' mipi_dsi_device. This device is populated with the desired DSI params, which are passed on to the host via mipi_dsi_attach().
This method will require the device driver to get a phandle to the DSI host since there is no parent-child relation between the two.
Is there a better way to do this? Please let me know!
Archit Taneja (2): drm/dsi: Create dummy DSI devices drm/dsi: Get DSI host by DT device node
drivers/gpu/drm/drm_mipi_dsi.c | 108 ++++++++++++++++++++++++++++++++++++++++- include/drm/drm_mipi_dsi.h | 4 ++ 2 files changed, 110 insertions(+), 2 deletions(-)
We can have devices where the data bus is MIPI DSI, but the control bus is something else (i2c, spi etc). A typical example is i2c controlled encoder bridge chips.
Such devices too require passing DSI specific parameters (number of data lanes, DSI mode flags, color format etc) to their DSI host. For a device that isn't 'mipi_dsi_device', there is no way of passing such parameters.
Provide the option of creating a dummy DSI device. The main purpose of this would be to attach to a DSI host by calling mipi_dsi_attach, and pass DSI params.
Create mipi_dsi_new_dummy for creating a dummy dsi device. The driver calling this needs to be aware of the mipi_dsi_host it wants to attach to, and also the DSI virtual channel the DSI device intends to use.
Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 78 ++++++++++++++++++++++++++++++++++++++++-- include/drm/drm_mipi_dsi.h | 2 ++ 2 files changed, 78 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 2d5ca8ee..9bfe215 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -47,7 +47,14 @@
static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv) { - return of_driver_match_device(dev, drv); + if (of_driver_match_device(dev, drv)) + return 1; + + if (!strcmp(drv->name, "mipi_dsi_dummy") && + strstr(dev_name(dev), "dummy_dev")) + return 1; + + return 0; }
static const struct dev_pm_ops mipi_dsi_device_pm_ops = { @@ -171,6 +178,67 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) return dsi; }
+static int dummy_probe(struct mipi_dsi_device *dsi) +{ + return 0; +} + +static int dummy_remove(struct mipi_dsi_device *dsi) +{ + return 0; +} + +static void dummy_shutdown(struct mipi_dsi_device *dsi) +{ +} + +static struct mipi_dsi_driver dummy_dsi_driver = { + .probe = dummy_probe, + .remove = dummy_remove, + .shutdown = dummy_shutdown, + .driver.name = "mipi_dsi_dummy", +}; + +static int mipi_dsi_device_add_dummy(struct mipi_dsi_device *dsi) +{ + struct mipi_dsi_host *host = dsi->host; + + dev_set_name(&dsi->dev, "%s.dummy_dev.%d", dev_name(host->dev), + dsi->channel); + + return device_add(&dsi->dev); +} + +struct mipi_dsi_device *mipi_dsi_new_dummy(struct mipi_dsi_host *host, u32 reg) +{ + struct mipi_dsi_device *dsi; + struct device *dev = host->dev; + int ret; + + if (reg > 3) { + dev_err(dev, "invalid reg property %u\n", reg); + return ERR_PTR(-EINVAL); + } + + dsi = mipi_dsi_device_alloc(host); + if (IS_ERR(dsi)) { + dev_err(dev, "failed to allocate dummy DSI device %ld\n", + PTR_ERR(dsi)); + return dsi; + } + + dsi->channel = reg; + + ret = mipi_dsi_device_add_dummy(dsi); + if (ret) { + dev_err(dev, "failed to add dummy DSI device %d\n", ret); + kfree(dsi); + return ERR_PTR(ret); + } + + return dsi; +} + int mipi_dsi_host_register(struct mipi_dsi_host *host) { struct device_node *node; @@ -924,7 +992,13 @@ EXPORT_SYMBOL(mipi_dsi_driver_unregister);
static int __init mipi_dsi_bus_init(void) { - return bus_register(&mipi_dsi_bus_type); + int ret; + + ret = bus_register(&mipi_dsi_bus_type); + if (ret < 0) + return ret; + + return mipi_dsi_driver_register(&dummy_dsi_driver); } postcore_initcall(mipi_dsi_bus_init);
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index f1d8d0d..d06ba99 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -174,6 +174,8 @@ ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload, ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params, size_t num_params, void *data, size_t size);
+struct mipi_dsi_device *mipi_dsi_new_dummy(struct mipi_dsi_host *host, u32 reg); + /** * enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode * @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking
On 06/30/2015 07:24 AM, Archit Taneja wrote:
We can have devices where the data bus is MIPI DSI, but the control bus is something else (i2c, spi etc). A typical example is i2c controlled encoder bridge chips.
Such devices too require passing DSI specific parameters (number of data lanes, DSI mode flags, color format etc) to their DSI host. For a device that isn't 'mipi_dsi_device', there is no way of passing such parameters.
Provide the option of creating a dummy DSI device. The main purpose of this would be to attach to a DSI host by calling mipi_dsi_attach, and pass DSI params.
Create mipi_dsi_new_dummy for creating a dummy dsi device. The driver calling this needs to be aware of the mipi_dsi_host it wants to attach to, and also the DSI virtual channel the DSI device intends to use.
Signed-off-by: Archit Taneja architt@codeaurora.org
drivers/gpu/drm/drm_mipi_dsi.c | 78 ++++++++++++++++++++++++++++++++++++++++-- include/drm/drm_mipi_dsi.h | 2 ++ 2 files changed, 78 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 2d5ca8ee..9bfe215 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -47,7 +47,14 @@
static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv) {
- return of_driver_match_device(dev, drv);
- if (of_driver_match_device(dev, drv))
return 1;
- if (!strcmp(drv->name, "mipi_dsi_dummy") &&
strstr(dev_name(dev), "dummy_dev"))
return 1;
Is this kind of fuzzy matching used in other dummy devs? It looks little bit scary. You can at least replace
strstr(dev_name(dev), "dummy_dev"))
with
strstr(dev_name(dev), ".dummy_dev."))
Anyway, currently it should not break anything, am I right?
- return 0;
}
static const struct dev_pm_ops mipi_dsi_device_pm_ops = { @@ -171,6 +178,67 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) return dsi; }
+static int dummy_probe(struct mipi_dsi_device *dsi) +{
- return 0;
+}
+static int dummy_remove(struct mipi_dsi_device *dsi) +{
- return 0;
+}
+static void dummy_shutdown(struct mipi_dsi_device *dsi) +{ +}
I suppose these callbacks are optional, so you can omit them.
+static struct mipi_dsi_driver dummy_dsi_driver = {
- .probe = dummy_probe,
- .remove = dummy_remove,
- .shutdown = dummy_shutdown,
- .driver.name = "mipi_dsi_dummy",
+};
+static int mipi_dsi_device_add_dummy(struct mipi_dsi_device *dsi) +{
- struct mipi_dsi_host *host = dsi->host;
- dev_set_name(&dsi->dev, "%s.dummy_dev.%d", dev_name(host->dev),
dsi->channel);
- return device_add(&dsi->dev);
+}
+struct mipi_dsi_device *mipi_dsi_new_dummy(struct mipi_dsi_host *host, u32 reg) +{
- struct mipi_dsi_device *dsi;
- struct device *dev = host->dev;
- int ret;
- if (reg > 3) {
dev_err(dev, "invalid reg property %u\n", reg);
return ERR_PTR(-EINVAL);
- }
- dsi = mipi_dsi_device_alloc(host);
- if (IS_ERR(dsi)) {
dev_err(dev, "failed to allocate dummy DSI device %ld\n",
PTR_ERR(dsi));
return dsi;
- }
- dsi->channel = reg;
- ret = mipi_dsi_device_add_dummy(dsi);
- if (ret) {
dev_err(dev, "failed to add dummy DSI device %d\n", ret);
kfree(dsi);
return ERR_PTR(ret);
- }
- return dsi;
+}
int mipi_dsi_host_register(struct mipi_dsi_host *host) { struct device_node *node; @@ -924,7 +992,13 @@ EXPORT_SYMBOL(mipi_dsi_driver_unregister);
static int __init mipi_dsi_bus_init(void) {
- return bus_register(&mipi_dsi_bus_type);
- int ret;
- ret = bus_register(&mipi_dsi_bus_type);
- if (ret < 0)
return ret;
- return mipi_dsi_driver_register(&dummy_dsi_driver);
} postcore_initcall(mipi_dsi_bus_init);
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index f1d8d0d..d06ba99 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -174,6 +174,8 @@ ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload, ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params, size_t num_params, void *data, size_t size);
+struct mipi_dsi_device *mipi_dsi_new_dummy(struct mipi_dsi_host *host, u32 reg);
/**
- enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode
- @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking
Hi,
On 08/19/2015 01:40 PM, Andrzej Hajda wrote:
On 06/30/2015 07:24 AM, Archit Taneja wrote:
We can have devices where the data bus is MIPI DSI, but the control bus is something else (i2c, spi etc). A typical example is i2c controlled encoder bridge chips.
Such devices too require passing DSI specific parameters (number of data lanes, DSI mode flags, color format etc) to their DSI host. For a device that isn't 'mipi_dsi_device', there is no way of passing such parameters.
Provide the option of creating a dummy DSI device. The main purpose of this would be to attach to a DSI host by calling mipi_dsi_attach, and pass DSI params.
Create mipi_dsi_new_dummy for creating a dummy dsi device. The driver calling this needs to be aware of the mipi_dsi_host it wants to attach to, and also the DSI virtual channel the DSI device intends to use.
Signed-off-by: Archit Taneja architt@codeaurora.org
drivers/gpu/drm/drm_mipi_dsi.c | 78 ++++++++++++++++++++++++++++++++++++++++-- include/drm/drm_mipi_dsi.h | 2 ++ 2 files changed, 78 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 2d5ca8ee..9bfe215 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -47,7 +47,14 @@
static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv) {
- return of_driver_match_device(dev, drv);
- if (of_driver_match_device(dev, drv))
return 1;
- if (!strcmp(drv->name, "mipi_dsi_dummy") &&
strstr(dev_name(dev), "dummy_dev"))
return 1;
Is this kind of fuzzy matching used in other dummy devs? It looks little bit scary. You can at least replace
strstr(dev_name(dev), "dummy_dev"))
with
strstr(dev_name(dev), ".dummy_dev."))
Anyway, currently it should not break anything, am I right?
I took i2c's dummy dev creation as reference. The i2c_driver struct has an id_table param, that allows the match function (i2c_device_match) to not have a special case to check for a dummy device.
We could a 'id_table' entry in mipi_dsi_driver, and a 'name' entry in mipi_dsi_device. But that would be a bit of an overkill just to support dummy devices.
I could make the check more thorough by adding a func which does something similar to 'i2c_verify_client', but I think we would still need the above string.
I will change "dummy_dev" to ".dummy_dev.". I grepped the kernel for devices named "dummy_dev", but didn't find anything as such, so it shouldn't really break anything.
return 0; }
static const struct dev_pm_ops mipi_dsi_device_pm_ops = {
@@ -171,6 +178,67 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) return dsi; }
+static int dummy_probe(struct mipi_dsi_device *dsi) +{
- return 0;
+}
+static int dummy_remove(struct mipi_dsi_device *dsi) +{
- return 0;
+}
+static void dummy_shutdown(struct mipi_dsi_device *dsi) +{ +}
I suppose these callbacks are optional, so you can omit them.
Right. I will remove these.
Thanks for the review.
Archit
mipi_dsi_devices are inherently aware of their host because they share a parent-child hierarchy in the device tree.
Non-dsi drivers that create a dummy dsi device don't have this data. In order to get this information, they require to a phandle to the dsi host in the device tree.
Maintain a list of all the hosts DSI that are currently registered.
This list will be used to find the mipi_dsi_host corresponding to the device_node passed in of_find_mipi_dsi_host_by_node.
Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 30 ++++++++++++++++++++++++++++++ include/drm/drm_mipi_dsi.h | 2 ++ 2 files changed, 32 insertions(+)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 9bfe215..81ddb73 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -239,6 +239,28 @@ struct mipi_dsi_device *mipi_dsi_new_dummy(struct mipi_dsi_host *host, u32 reg) return dsi; }
+static DEFINE_MUTEX(host_lock); +static LIST_HEAD(host_list); + +struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node) +{ + struct mipi_dsi_host *host; + + mutex_lock(&host_lock); + + list_for_each_entry(host, &host_list, list) { + if (host->dev->of_node == node) { + mutex_unlock(&host_lock); + return host; + } + } + + mutex_unlock(&host_lock); + + return NULL; +} +EXPORT_SYMBOL(of_find_mipi_dsi_host_by_node); + int mipi_dsi_host_register(struct mipi_dsi_host *host) { struct device_node *node; @@ -250,6 +272,10 @@ int mipi_dsi_host_register(struct mipi_dsi_host *host) of_mipi_dsi_device_add(host, node); }
+ mutex_lock(&host_lock); + list_add_tail(&host->list, &host_list); + mutex_unlock(&host_lock); + return 0; } EXPORT_SYMBOL(mipi_dsi_host_register); @@ -266,6 +292,10 @@ static int mipi_dsi_remove_device_fn(struct device *dev, void *priv) void mipi_dsi_host_unregister(struct mipi_dsi_host *host) { device_for_each_child(host->dev, NULL, mipi_dsi_remove_device_fn); + + mutex_lock(&host_lock); + list_del_init(&host->list); + mutex_unlock(&host_lock); } EXPORT_SYMBOL(mipi_dsi_host_unregister);
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index d06ba99..1684a0e 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -100,10 +100,12 @@ struct mipi_dsi_host_ops { struct mipi_dsi_host { struct device *dev; const struct mipi_dsi_host_ops *ops; + struct list_head list; };
int mipi_dsi_host_register(struct mipi_dsi_host *host); void mipi_dsi_host_unregister(struct mipi_dsi_host *host); +struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node);
/* DSI mode flags */
On 06/30/2015 07:24 AM, Archit Taneja wrote:
mipi_dsi_devices are inherently aware of their host because they share a parent-child hierarchy in the device tree.
Non-dsi drivers that create a dummy dsi device don't have this data. In order to get this information, they require to a phandle to the dsi host in the device tree.
Maintain a list of all the hosts DSI that are currently registered.
This list will be used to find the mipi_dsi_host corresponding to the device_node passed in of_find_mipi_dsi_host_by_node.
The lock protects only the list, there is no guarantee that mipi_dsi_host returned by of_find_mipi_dsi_host_by_node is still valid, or will be valid long enough.
But this issue affects many kernel frameworks so I am not sure if it should block this particular patch.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com
Regards Andrzej
Signed-off-by: Archit Taneja architt@codeaurora.org
drivers/gpu/drm/drm_mipi_dsi.c | 30 ++++++++++++++++++++++++++++++ include/drm/drm_mipi_dsi.h | 2 ++ 2 files changed, 32 insertions(+)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 9bfe215..81ddb73 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -239,6 +239,28 @@ struct mipi_dsi_device *mipi_dsi_new_dummy(struct mipi_dsi_host *host, u32 reg) return dsi; }
+static DEFINE_MUTEX(host_lock); +static LIST_HEAD(host_list);
+struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node) +{
- struct mipi_dsi_host *host;
- mutex_lock(&host_lock);
- list_for_each_entry(host, &host_list, list) {
if (host->dev->of_node == node) {
mutex_unlock(&host_lock);
return host;
}
- }
- mutex_unlock(&host_lock);
- return NULL;
+} +EXPORT_SYMBOL(of_find_mipi_dsi_host_by_node);
int mipi_dsi_host_register(struct mipi_dsi_host *host) { struct device_node *node; @@ -250,6 +272,10 @@ int mipi_dsi_host_register(struct mipi_dsi_host *host) of_mipi_dsi_device_add(host, node); }
- mutex_lock(&host_lock);
- list_add_tail(&host->list, &host_list);
- mutex_unlock(&host_lock);
- return 0;
} EXPORT_SYMBOL(mipi_dsi_host_register); @@ -266,6 +292,10 @@ static int mipi_dsi_remove_device_fn(struct device *dev, void *priv) void mipi_dsi_host_unregister(struct mipi_dsi_host *host) { device_for_each_child(host->dev, NULL, mipi_dsi_remove_device_fn);
- mutex_lock(&host_lock);
- list_del_init(&host->list);
- mutex_unlock(&host_lock);
} EXPORT_SYMBOL(mipi_dsi_host_unregister);
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index d06ba99..1684a0e 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -100,10 +100,12 @@ struct mipi_dsi_host_ops { struct mipi_dsi_host { struct device *dev; const struct mipi_dsi_host_ops *ops;
- struct list_head list;
};
int mipi_dsi_host_register(struct mipi_dsi_host *host); void mipi_dsi_host_unregister(struct mipi_dsi_host *host); +struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node);
/* DSI mode flags */
Hi,
On 06/30/2015 10:54 AM, Archit Taneja wrote:
We are currently restricted when it comes to supporting DSI on devices that have a non-DSI control bus. For example, DSI encoder chips are available in the market that are configured via i2c. Configuring their registers via DSI bus is either optional or not available at all.
These devices still need to pass DSI parameters (data lanes, mode flags etc) to the DSI host they are connected to. We don't have a way to do that at the moment.
The method presented in these patches is to provide an API to create a 'dummy' mipi_dsi_device. This device is populated with the desired DSI params, which are passed on to the host via mipi_dsi_attach().
This method will require the device driver to get a phandle to the DSI host since there is no parent-child relation between the two.
Is there a better way to do this? Please let me know!
Any comments on this?
Archit
Archit Taneja (2): drm/dsi: Create dummy DSI devices drm/dsi: Get DSI host by DT device node
drivers/gpu/drm/drm_mipi_dsi.c | 108 ++++++++++++++++++++++++++++++++++++++++- include/drm/drm_mipi_dsi.h | 4 ++ 2 files changed, 110 insertions(+), 2 deletions(-)
On Wed, Aug 19, 2015 at 10:37:54AM +0530, Archit Taneja wrote:
Hi,
On 06/30/2015 10:54 AM, Archit Taneja wrote:
We are currently restricted when it comes to supporting DSI on devices that have a non-DSI control bus. For example, DSI encoder chips are available in the market that are configured via i2c. Configuring their registers via DSI bus is either optional or not available at all.
These devices still need to pass DSI parameters (data lanes, mode flags etc) to the DSI host they are connected to. We don't have a way to do that at the moment.
The method presented in these patches is to provide an API to create a 'dummy' mipi_dsi_device. This device is populated with the desired DSI params, which are passed on to the host via mipi_dsi_attach().
This method will require the device driver to get a phandle to the DSI host since there is no parent-child relation between the two.
Is there a better way to do this? Please let me know!
Any comments on this?
Perhaps a better way would be to invert this relationship. According to your proposal we'd have to have DT like this:
i2c@... { ...
dsi-device@... { ... dsi-bus = <&dsi>; ... };
... };
dsi@... { ... };
Inversing the relationship would become something like this:
i2c@... { ... };
dsi@... { ...
peripheral@... { ... i2c-bus = <&i2c>; ... };
... };
Both of those aren't fundamentally different, and they both have the disavantage of lacking ways to transport configuration data that the other bus needs to instantiate the dummy device (such as the reg property for example, denoting the I2C slave address or the DSI VC).
So how about we create two devices in the device tree and fuse them at the driver level:
i2c@... { ...
i2cdsi: dsi-device@... { ... };
... };
dsi@... { ...
peripheral@... { ... control = <&i2cdsi>; ... };
... };
This way we'll get both an I2C device and a DSI device that we can fully describe using the standard device tree bindings. At driver time we can get the I2C device from the phandle in the control property of the DSI device and use it to execute I2C transactions.
Thierry
Hi Thierry, Archit,
Am Mittwoch, den 19.08.2015, 15:13 +0200 schrieb Thierry Reding:
On Wed, Aug 19, 2015 at 10:37:54AM +0530, Archit Taneja wrote:
Hi,
On 06/30/2015 10:54 AM, Archit Taneja wrote:
We are currently restricted when it comes to supporting DSI on devices that have a non-DSI control bus. For example, DSI encoder chips are available in the market that are configured via i2c. Configuring their registers via DSI bus is either optional or not available at all.
These devices still need to pass DSI parameters (data lanes, mode flags etc) to the DSI host they are connected to. We don't have a way to do that at the moment.
The method presented in these patches is to provide an API to create a 'dummy' mipi_dsi_device. This device is populated with the desired DSI params, which are passed on to the host via mipi_dsi_attach().
This method will require the device driver to get a phandle to the DSI host since there is no parent-child relation between the two.
Is there a better way to do this? Please let me know!
Any comments on this?
Perhaps a better way would be to invert this relationship. According to your proposal we'd have to have DT like this:
i2c@... { ...
dsi-device@... { ... dsi-bus = <&dsi>; ... }; ...
};
dsi@... { ... };
Inversing the relationship would become something like this:
i2c@... { ... };
dsi@... { ...
peripheral@... { ... i2c-bus = <&i2c>; ... }; ...
};
Both of those aren't fundamentally different, and they both have the disavantage of lacking ways to transport configuration data that the other bus needs to instantiate the dummy device (such as the reg property for example, denoting the I2C slave address or the DSI VC).
So how about we create two devices in the device tree and fuse them at the driver level:
i2c@... { ...
i2cdsi: dsi-device@... { ... }; ...
};
dsi@... { ...
peripheral@... { ... control = <&i2cdsi>; ... }; ...
};
This way we'll get both an I2C device and a DSI device that we can fully describe using the standard device tree bindings. At driver time we can get the I2C device from the phandle in the control property of the DSI device and use it to execute I2C transactions.
I don't really like to see that you are inventing yet-another-way to handle devices connected to multiple buses.
Devicetree is structured along the control buses, even if the devices are connected to multiple buses, in the DT they are always children of the bus that is used to control their registers from the CPUs perspective. So a DSI encoder that is controlled through i2c is clearly a child of the i2c master controller and only of that one.
If you need to model connections between devices that are not reflected through the control bus hierarchy you should really consider using the standardized of-graph bindings. (Documentation/devicetree/bindings/graph.txt)
Multiple device drivers in both the media and DRM universe have shown that they are a working way to represent those data bus connections between devices. I know this might make things a bit more complicated for Tegra DRM, where you have a nice parent<->child relationship between the components even on the control path so far, but we should really move into the direction of more drivers using the standardized bindings for this stuff, instead of doing another round of NIH.
Regards, Lucas
On Wed, Aug 19, 2015 at 04:17:08PM +0200, Lucas Stach wrote:
Hi Thierry, Archit,
Am Mittwoch, den 19.08.2015, 15:13 +0200 schrieb Thierry Reding:
On Wed, Aug 19, 2015 at 10:37:54AM +0530, Archit Taneja wrote:
Hi,
On 06/30/2015 10:54 AM, Archit Taneja wrote:
We are currently restricted when it comes to supporting DSI on devices that have a non-DSI control bus. For example, DSI encoder chips are available in the market that are configured via i2c. Configuring their registers via DSI bus is either optional or not available at all.
These devices still need to pass DSI parameters (data lanes, mode flags etc) to the DSI host they are connected to. We don't have a way to do that at the moment.
The method presented in these patches is to provide an API to create a 'dummy' mipi_dsi_device. This device is populated with the desired DSI params, which are passed on to the host via mipi_dsi_attach().
This method will require the device driver to get a phandle to the DSI host since there is no parent-child relation between the two.
Is there a better way to do this? Please let me know!
Any comments on this?
Perhaps a better way would be to invert this relationship. According to your proposal we'd have to have DT like this:
i2c@... { ...
dsi-device@... { ... dsi-bus = <&dsi>; ... }; ...
};
dsi@... { ... };
Inversing the relationship would become something like this:
i2c@... { ... };
dsi@... { ...
peripheral@... { ... i2c-bus = <&i2c>; ... }; ...
};
Both of those aren't fundamentally different, and they both have the disavantage of lacking ways to transport configuration data that the other bus needs to instantiate the dummy device (such as the reg property for example, denoting the I2C slave address or the DSI VC).
So how about we create two devices in the device tree and fuse them at the driver level:
i2c@... { ...
i2cdsi: dsi-device@... { ... }; ...
};
dsi@... { ...
peripheral@... { ... control = <&i2cdsi>; ... }; ...
};
This way we'll get both an I2C device and a DSI device that we can fully describe using the standard device tree bindings. At driver time we can get the I2C device from the phandle in the control property of the DSI device and use it to execute I2C transactions.
I don't really like to see that you are inventing yet-another-way to handle devices connected to multiple buses.
Devicetree is structured along the control buses, even if the devices are connected to multiple buses, in the DT they are always children of the bus that is used to control their registers from the CPUs perspective. So a DSI encoder that is controlled through i2c is clearly a child of the i2c master controller and only of that one.
I think that's a flawed interpretation of what's going on here. The device in fact has two interfaces: one is I2C, the other is DSI. In my opinion that's reason enough to represent it as two logical devices.
If you need to model connections between devices that are not reflected through the control bus hierarchy you should really consider using the standardized of-graph bindings. (Documentation/devicetree/bindings/graph.txt)
The problem is that the original proposal would instantiate a dummy device, so it wouldn't be represented in DT at all. So unless you do add two logical devices to DT (one for each bus interface), you don't have anything to glue together with an OF graph.
Multiple device drivers in both the media and DRM universe have shown that they are a working way to represent those data bus connections between devices. I know this might make things a bit more complicated for Tegra DRM, where you have a nice parent<->child relationship between the components even on the control path so far, but we should really move into the direction of more drivers using the standardized bindings for this stuff, instead of doing another round of NIH.
Why are you bringing up Tegra DRM? I don't see how it's relevant in any way to this discussion.
Thierry
Am Mittwoch, den 19.08.2015, 16:34 +0200 schrieb Thierry Reding:
On Wed, Aug 19, 2015 at 04:17:08PM +0200, Lucas Stach wrote:
Hi Thierry, Archit,
[...]
Perhaps a better way would be to invert this relationship. According to your proposal we'd have to have DT like this:
i2c@... { ...
dsi-device@... { ... dsi-bus = <&dsi>; ... }; ...
};
dsi@... { ... };
Inversing the relationship would become something like this:
i2c@... { ... };
dsi@... { ...
peripheral@... { ... i2c-bus = <&i2c>; ... }; ...
};
Both of those aren't fundamentally different, and they both have the disavantage of lacking ways to transport configuration data that the other bus needs to instantiate the dummy device (such as the reg property for example, denoting the I2C slave address or the DSI VC).
So how about we create two devices in the device tree and fuse them at the driver level:
i2c@... { ...
i2cdsi: dsi-device@... { ... }; ...
};
dsi@... { ...
peripheral@... { ... control = <&i2cdsi>; ... }; ...
};
This way we'll get both an I2C device and a DSI device that we can fully describe using the standard device tree bindings. At driver time we can get the I2C device from the phandle in the control property of the DSI device and use it to execute I2C transactions.
I don't really like to see that you are inventing yet-another-way to handle devices connected to multiple buses.
Devicetree is structured along the control buses, even if the devices are connected to multiple buses, in the DT they are always children of the bus that is used to control their registers from the CPUs perspective. So a DSI encoder that is controlled through i2c is clearly a child of the i2c master controller and only of that one.
I think that's a flawed interpretation of what's going on here. The device in fact has two interfaces: one is I2C, the other is DSI. In my opinion that's reason enough to represent it as two logical devices.
Does it really have 2 control interfaces that are used at the same time? Or is the DSI connection a passive data bus if the register control happens through i2c?
If you need to model connections between devices that are not reflected through the control bus hierarchy you should really consider using the standardized of-graph bindings. (Documentation/devicetree/bindings/graph.txt)
The problem is that the original proposal would instantiate a dummy device, so it wouldn't be represented in DT at all. So unless you do add two logical devices to DT (one for each bus interface), you don't have anything to glue together with an OF graph.
I see that the having dummy device is the least desirable solution. But if there is only one control bus to the device I think it should be one device sitting beneath the control bus.
You can then use of-graph to model the data path between the DSI encoder and device.
Multiple device drivers in both the media and DRM universe have shown that they are a working way to represent those data bus connections between devices. I know this might make things a bit more complicated for Tegra DRM, where you have a nice parent<->child relationship between the components even on the control path so far, but we should really move into the direction of more drivers using the standardized bindings for this stuff, instead of doing another round of NIH.
Why are you bringing up Tegra DRM? I don't see how it's relevant in any way to this discussion.
Just disregard this comment then. Lets concentrate on the points above.
Regards, Lucas
On Wed, Aug 19, 2015 at 04:52:24PM +0200, Lucas Stach wrote:
Am Mittwoch, den 19.08.2015, 16:34 +0200 schrieb Thierry Reding:
On Wed, Aug 19, 2015 at 04:17:08PM +0200, Lucas Stach wrote:
Hi Thierry, Archit,
[...]
Perhaps a better way would be to invert this relationship. According to your proposal we'd have to have DT like this:
i2c@... { ...
dsi-device@... { ... dsi-bus = <&dsi>; ... }; ...
};
dsi@... { ... };
Inversing the relationship would become something like this:
i2c@... { ... };
dsi@... { ...
peripheral@... { ... i2c-bus = <&i2c>; ... }; ...
};
Both of those aren't fundamentally different, and they both have the disavantage of lacking ways to transport configuration data that the other bus needs to instantiate the dummy device (such as the reg property for example, denoting the I2C slave address or the DSI VC).
So how about we create two devices in the device tree and fuse them at the driver level:
i2c@... { ...
i2cdsi: dsi-device@... { ... }; ...
};
dsi@... { ...
peripheral@... { ... control = <&i2cdsi>; ... }; ...
};
This way we'll get both an I2C device and a DSI device that we can fully describe using the standard device tree bindings. At driver time we can get the I2C device from the phandle in the control property of the DSI device and use it to execute I2C transactions.
I don't really like to see that you are inventing yet-another-way to handle devices connected to multiple buses.
Devicetree is structured along the control buses, even if the devices are connected to multiple buses, in the DT they are always children of the bus that is used to control their registers from the CPUs perspective. So a DSI encoder that is controlled through i2c is clearly a child of the i2c master controller and only of that one.
I think that's a flawed interpretation of what's going on here. The device in fact has two interfaces: one is I2C, the other is DSI. In my opinion that's reason enough to represent it as two logical devices.
Does it really have 2 control interfaces that are used at the same time? Or is the DSI connection a passive data bus if the register control happens through i2c?
The interfaces may not be used at the same time, and the DSI interface may even be crippled, but the device is still addressable from the DSI host controller, if for nothing else than for routing the video stream.
If you need to model connections between devices that are not reflected through the control bus hierarchy you should really consider using the standardized of-graph bindings. (Documentation/devicetree/bindings/graph.txt)
The problem is that the original proposal would instantiate a dummy device, so it wouldn't be represented in DT at all. So unless you do add two logical devices to DT (one for each bus interface), you don't have anything to glue together with an OF graph.
I see that the having dummy device is the least desirable solution. But if there is only one control bus to the device I think it should be one device sitting beneath the control bus.
You can then use of-graph to model the data path between the DSI encoder and device.
But you will be needing a device below the DSI host controller to represent that endpoint of the connection. The DSI host controller itself is in no way connected to the I2C adapter. You would have to add some sort of quirk to the DSI controller binding to allow it to hook up with a control endpoint. And then you'll need more quirks to describe what kind of DSI device this is.
On the other hand if you properly instantiate the DSI device you can easily write a driver for it, and the driver will set up the correct properties as implied by the compatible string. Once you have that you can easily hook it up to the I2C control interface in whatever way you like, be that an OF graph or just a simple unidirectional link by phandle.
Thierry
On Wed, 19 Aug 2015, Thierry Reding treding@nvidia.com wrote:
On Wed, Aug 19, 2015 at 04:52:24PM +0200, Lucas Stach wrote:
Am Mittwoch, den 19.08.2015, 16:34 +0200 schrieb Thierry Reding:
I think that's a flawed interpretation of what's going on here. The device in fact has two interfaces: one is I2C, the other is DSI. In my opinion that's reason enough to represent it as two logical devices.
Does it really have 2 control interfaces that are used at the same time? Or is the DSI connection a passive data bus if the register control happens through i2c?
The interfaces may not be used at the same time, and the DSI interface may even be crippled, but the device is still addressable from the DSI host controller, if for nothing else than for routing the video stream.
As a drive-by comment, the Toshiba TC358764XBG/65XBG chip can be configured via both DSI and I2C. The I2C interface requires DSI clock on the DSI interface to operate. You may not use the interfaces simultaneously, but provided you protect against races in register access, both interfaces can be operational at the same time.
Sorry I couldn't find a public spec of the chip to share.
HTH, Jani.
Hi Thierry, Lucas,
On 08/19/2015 08:32 PM, Thierry Reding wrote:
On Wed, Aug 19, 2015 at 04:52:24PM +0200, Lucas Stach wrote:
Am Mittwoch, den 19.08.2015, 16:34 +0200 schrieb Thierry Reding:
On Wed, Aug 19, 2015 at 04:17:08PM +0200, Lucas Stach wrote:
Hi Thierry, Archit,
[...]
Perhaps a better way would be to invert this relationship. According to your proposal we'd have to have DT like this:
i2c@... { ...
dsi-device@... { ... dsi-bus = <&dsi>; ... }; ...
};
dsi@... { ... };
Inversing the relationship would become something like this:
i2c@... { ... };
dsi@... { ...
peripheral@... { ... i2c-bus = <&i2c>; ... }; ...
};
Both of those aren't fundamentally different, and they both have the disavantage of lacking ways to transport configuration data that the other bus needs to instantiate the dummy device (such as the reg property for example, denoting the I2C slave address or the DSI VC).
So how about we create two devices in the device tree and fuse them at the driver level:
i2c@... { ...
i2cdsi: dsi-device@... { ... }; ...
};
dsi@... { ...
peripheral@... { ... control = <&i2cdsi>; ... }; ...
};
This way we'll get both an I2C device and a DSI device that we can fully describe using the standard device tree bindings. At driver time we can get the I2C device from the phandle in the control property of the DSI device and use it to execute I2C transactions.
I don't really like to see that you are inventing yet-another-way to handle devices connected to multiple buses.
Devicetree is structured along the control buses, even if the devices are connected to multiple buses, in the DT they are always children of the bus that is used to control their registers from the CPUs perspective. So a DSI encoder that is controlled through i2c is clearly a child of the i2c master controller and only of that one.
I think that's a flawed interpretation of what's going on here. The device in fact has two interfaces: one is I2C, the other is DSI. In my opinion that's reason enough to represent it as two logical devices.
Does it really have 2 control interfaces that are used at the same time? Or is the DSI connection a passive data bus if the register control happens through i2c?
The interfaces may not be used at the same time, and the DSI interface may even be crippled, but the device is still addressable from the DSI host controller, if for nothing else than for routing the video stream.
If you need to model connections between devices that are not reflected through the control bus hierarchy you should really consider using the standardized of-graph bindings. (Documentation/devicetree/bindings/graph.txt)
The problem is that the original proposal would instantiate a dummy device, so it wouldn't be represented in DT at all. So unless you do add two logical devices to DT (one for each bus interface), you don't have anything to glue together with an OF graph.
I see that the having dummy device is the least desirable solution. But if there is only one control bus to the device I think it should be one device sitting beneath the control bus.
You can then use of-graph to model the data path between the DSI encoder and device.
But you will be needing a device below the DSI host controller to represent that endpoint of the connection. The DSI host controller itself is in no way connected to the I2C adapter. You would have to add some sort of quirk to the DSI controller binding to allow it to
Thanks for the review.
I implemented this to support ADV7533 DSI to HDMI encoder chip, which has a DSI video bus and an i2c control bus.
There weren't any quirks as such in the device tree when I tried to implement this. The DT seems to manage fine without a node corresponding to a mipi_dsi_device:
i2c_adap@.. { adv7533@.. {
port { adv_in: endpoint { remote-endpoint = <&dsi_out>; }; }; }; };
dsi_host@.. { ... ...
port { dsi_out: endpoint { remote-endpoint = <&adv_in>; } }; };
It's the i2c driver's job to parse the graph and retrieve the phandle to the dsi host. Using this, it can proceed with registering itself to this host using the new dsi funcs. This patch does the same for the adv7533 i2c driver:
http://www.spinics.net/lists/dri-devel/msg86840.html
hook up with a control endpoint. And then you'll need more quirks to describe what kind of DSI device this is.
Could you explain what you meant by this? I.e. describing the kind of DSI device?
The dsi device created isn't really a dummy device as such. It's dummy in the sense that there isn't a real dsi driver associated with it. The dsi device is still used to attach to a mipi dsi host, the way normal dsi devices do.
On the other hand if you properly instantiate the DSI device you can easily write a driver for it, and the driver will set up the correct properties as implied by the compatible string. Once you have that you can easily hook it up to the I2C control interface in whatever way you like, be that an OF graph or just a simple unidirectional link by phandle.
With the fused approach you suggested, we would have 2 drivers: one i2c and the other dsi. The i2c client driver would be more or less minimal, preparing an i2c_client device for the dsi driver to use. Is my understanding correct?
We can do without dummy dsi devices with this method. But, representing a device with 2 DT nodes seems a bit off. We'd also need to compatible strings for the same device, one for the i2c part, and the other for the dsi part.
From an adv75xx driver perspective, it should also support the ADV7511 chip, which is a RGB/DPI to HDMI encoder. For adv7511, we don't need a DSI DT node. It would be a bit inconsistent to have the bindings require both DSI and I2C nodes for one chip, and only I2C node for the other, with both chips being supported by the same driver.
Thanks, Archit
On Thu, Aug 20, 2015 at 09:46:14AM +0530, Archit Taneja wrote:
Hi Thierry, Lucas,
On 08/19/2015 08:32 PM, Thierry Reding wrote:
On Wed, Aug 19, 2015 at 04:52:24PM +0200, Lucas Stach wrote:
Am Mittwoch, den 19.08.2015, 16:34 +0200 schrieb Thierry Reding:
On Wed, Aug 19, 2015 at 04:17:08PM +0200, Lucas Stach wrote:
Hi Thierry, Archit,
[...]
Perhaps a better way would be to invert this relationship. According to your proposal we'd have to have DT like this:
i2c@... { ...
dsi-device@... { ... dsi-bus = <&dsi>; ... }; ...
};
dsi@... { ... };
Inversing the relationship would become something like this:
i2c@... { ... };
dsi@... { ...
peripheral@... { ... i2c-bus = <&i2c>; ... }; ...
};
Both of those aren't fundamentally different, and they both have the disavantage of lacking ways to transport configuration data that the other bus needs to instantiate the dummy device (such as the reg property for example, denoting the I2C slave address or the DSI VC).
So how about we create two devices in the device tree and fuse them at the driver level:
i2c@... { ...
i2cdsi: dsi-device@... { ... }; ...
};
dsi@... { ...
peripheral@... { ... control = <&i2cdsi>; ... }; ...
};
This way we'll get both an I2C device and a DSI device that we can fully describe using the standard device tree bindings. At driver time we can get the I2C device from the phandle in the control property of the DSI device and use it to execute I2C transactions.
I don't really like to see that you are inventing yet-another-way to handle devices connected to multiple buses.
Devicetree is structured along the control buses, even if the devices are connected to multiple buses, in the DT they are always children of the bus that is used to control their registers from the CPUs perspective. So a DSI encoder that is controlled through i2c is clearly a child of the i2c master controller and only of that one.
I think that's a flawed interpretation of what's going on here. The device in fact has two interfaces: one is I2C, the other is DSI. In my opinion that's reason enough to represent it as two logical devices.
Does it really have 2 control interfaces that are used at the same time? Or is the DSI connection a passive data bus if the register control happens through i2c?
The interfaces may not be used at the same time, and the DSI interface may even be crippled, but the device is still addressable from the DSI host controller, if for nothing else than for routing the video stream.
If you need to model connections between devices that are not reflected through the control bus hierarchy you should really consider using the standardized of-graph bindings. (Documentation/devicetree/bindings/graph.txt)
The problem is that the original proposal would instantiate a dummy device, so it wouldn't be represented in DT at all. So unless you do add two logical devices to DT (one for each bus interface), you don't have anything to glue together with an OF graph.
I see that the having dummy device is the least desirable solution. But if there is only one control bus to the device I think it should be one device sitting beneath the control bus.
You can then use of-graph to model the data path between the DSI encoder and device.
But you will be needing a device below the DSI host controller to represent that endpoint of the connection. The DSI host controller itself is in no way connected to the I2C adapter. You would have to add some sort of quirk to the DSI controller binding to allow it to
Thanks for the review.
I implemented this to support ADV7533 DSI to HDMI encoder chip, which has a DSI video bus and an i2c control bus.
There weren't any quirks as such in the device tree when I tried to implement this. The DT seems to manage fine without a node corresponding to a mipi_dsi_device:
i2c_adap@.. { adv7533@.. {
port { adv_in: endpoint { remote-endpoint = <&dsi_out>; }; };
}; };
dsi_host@.. { ... ...
port { dsi_out: endpoint { remote-endpoint = <&adv_in>; } }; };
It's the i2c driver's job to parse the graph and retrieve the phandle to the dsi host. Using this, it can proceed with registering itself to this host using the new dsi funcs. This patch does the same for the adv7533 i2c driver:
http://www.spinics.net/lists/dri-devel/msg86840.html
hook up with a control endpoint. And then you'll need more quirks to describe what kind of DSI device this is.
Could you explain what you meant by this? I.e. describing the kind of DSI device?
Describing the number of lanes, specifying the virtual channel, mode flags, etc. You could probably set the number of lanes and mode flags via the I2C driver, but especially the virtual channel cannot be set because it isn't known to the I2C DT branch of the device.
The dsi device created isn't really a dummy device as such. It's dummy in the sense that there isn't a real dsi driver associated with it. The dsi device is still used to attach to a mipi dsi host, the way normal dsi devices do.
I understand, but I don't see why it has to be instantiated by the I2C driver, that's what I find backwards. There is already a standard way for instantiating DSI devices, why not use it?
On the other hand if you properly instantiate the DSI device you can easily write a driver for it, and the driver will set up the correct properties as implied by the compatible string. Once you have that you can easily hook it up to the I2C control interface in whatever way you like, be that an OF graph or just a simple unidirectional link by phandle.
With the fused approach you suggested, we would have 2 drivers: one i2c and the other dsi. The i2c client driver would be more or less minimal, preparing an i2c_client device for the dsi driver to use. Is my understanding correct?
Correct. That's kind of similar to the way an HDMI encoder driver would use an I2C adapter to query EDID. The i2c_client device would be a means for the DSI driver to access the control interface.
We can do without dummy dsi devices with this method. But, representing a device with 2 DT nodes seems a bit off. We'd also need to compatible strings for the same device, one for the i2c part, and the other for the dsi part.
I agree that this somewhat stretches the capabilities of device tree. Another alternative I guess would be to not have a compatible string for the I2C device at all (that's technically not valid, I guess) because we really don't need an I2C driver for the device. What we really need is a DSI driver with a means to talk over some I2C bus with some other part of its device.
From an adv75xx driver perspective, it should also support the ADV7511 chip, which is a RGB/DPI to HDMI encoder. For adv7511, we don't need a DSI DT node. It would be a bit inconsistent to have the bindings require both DSI and I2C nodes for one chip, and only I2C node for the other, with both chips being supported by the same driver.
Why would that be inconsistent? That sounds like the most accurate representation of the hardware to me.
Thierry
On 08/20/2015 05:18 PM, Thierry Reding wrote:
On Thu, Aug 20, 2015 at 09:46:14AM +0530, Archit Taneja wrote:
Hi Thierry, Lucas,
On 08/19/2015 08:32 PM, Thierry Reding wrote:
On Wed, Aug 19, 2015 at 04:52:24PM +0200, Lucas Stach wrote:
Am Mittwoch, den 19.08.2015, 16:34 +0200 schrieb Thierry Reding:
On Wed, Aug 19, 2015 at 04:17:08PM +0200, Lucas Stach wrote:
Hi Thierry, Archit,
[...]
> Perhaps a better way would be to invert this relationship. According to > your proposal we'd have to have DT like this: > > i2c@... { > ... > > dsi-device@... { > ... > dsi-bus = <&dsi>; > ... > }; > > ... > }; > > dsi@... { > ... > }; > > Inversing the relationship would become something like this: > > i2c@... { > ... > }; > > dsi@... { > ... > > peripheral@... { > ... > i2c-bus = <&i2c>; > ... > }; > > ... > }; > > Both of those aren't fundamentally different, and they both have the > disavantage of lacking ways to transport configuration data that the > other bus needs to instantiate the dummy device (such as the reg > property for example, denoting the I2C slave address or the DSI VC). > > So how about we create two devices in the device tree and fuse them at > the driver level: > > i2c@... { > ... > > i2cdsi: dsi-device@... { > ... > }; > > ... > }; > > dsi@... { > ... > > peripheral@... { > ... > control = <&i2cdsi>; > ... > }; > > ... > }; > > This way we'll get both an I2C device and a DSI device that we can fully > describe using the standard device tree bindings. At driver time we can > get the I2C device from the phandle in the control property of the DSI > device and use it to execute I2C transactions. > I don't really like to see that you are inventing yet-another-way to handle devices connected to multiple buses.
Devicetree is structured along the control buses, even if the devices are connected to multiple buses, in the DT they are always children of the bus that is used to control their registers from the CPUs perspective. So a DSI encoder that is controlled through i2c is clearly a child of the i2c master controller and only of that one.
I think that's a flawed interpretation of what's going on here. The device in fact has two interfaces: one is I2C, the other is DSI. In my opinion that's reason enough to represent it as two logical devices.
Does it really have 2 control interfaces that are used at the same time? Or is the DSI connection a passive data bus if the register control happens through i2c?
The interfaces may not be used at the same time, and the DSI interface may even be crippled, but the device is still addressable from the DSI host controller, if for nothing else than for routing the video stream.
If you need to model connections between devices that are not reflected through the control bus hierarchy you should really consider using the standardized of-graph bindings. (Documentation/devicetree/bindings/graph.txt)
The problem is that the original proposal would instantiate a dummy device, so it wouldn't be represented in DT at all. So unless you do add two logical devices to DT (one for each bus interface), you don't have anything to glue together with an OF graph.
I see that the having dummy device is the least desirable solution. But if there is only one control bus to the device I think it should be one device sitting beneath the control bus.
You can then use of-graph to model the data path between the DSI encoder and device.
But you will be needing a device below the DSI host controller to represent that endpoint of the connection. The DSI host controller itself is in no way connected to the I2C adapter. You would have to add some sort of quirk to the DSI controller binding to allow it to
Thanks for the review.
I implemented this to support ADV7533 DSI to HDMI encoder chip, which has a DSI video bus and an i2c control bus.
There weren't any quirks as such in the device tree when I tried to implement this. The DT seems to manage fine without a node corresponding to a mipi_dsi_device:
i2c_adap@.. { adv7533@.. {
port { adv_in: endpoint { remote-endpoint = <&dsi_out>; }; };
}; };
dsi_host@.. { ... ...
port { dsi_out: endpoint { remote-endpoint = <&adv_in>; } }; };
It's the i2c driver's job to parse the graph and retrieve the phandle to the dsi host. Using this, it can proceed with registering itself to this host using the new dsi funcs. This patch does the same for the adv7533 i2c driver:
http://www.spinics.net/lists/dri-devel/msg86840.html
hook up with a control endpoint. And then you'll need more quirks to describe what kind of DSI device this is.
Could you explain what you meant by this? I.e. describing the kind of DSI device?
Describing the number of lanes, specifying the virtual channel, mode flags, etc. You could probably set the number of lanes and mode flags via the I2C driver, but especially the virtual channel cannot be set because it isn't known to the I2C DT branch of the device.
I agree with the VC part. It could be a DT entry within the i2c client node, but that does make it seem like a quirk. The 'reg' way under the DSI host is definitely better to populate the virtual channel.
The dsi device created isn't really a dummy device as such. It's dummy in the sense that there isn't a real dsi driver associated with it. The dsi device is still used to attach to a mipi dsi host, the way normal dsi devices do.
I understand, but I don't see why it has to be instantiated by the I2C driver, that's what I find backwards. There is already a standard way for instantiating DSI devices, why not use it?
I assumed we could either represent the device using an i2c driver, or dsi, but not both. Hence, I came up with this approach.
On the other hand if you properly instantiate the DSI device you can easily write a driver for it, and the driver will set up the correct properties as implied by the compatible string. Once you have that you can easily hook it up to the I2C control interface in whatever way you like, be that an OF graph or just a simple unidirectional link by phandle.
With the fused approach you suggested, we would have 2 drivers: one i2c and the other dsi. The i2c client driver would be more or less minimal, preparing an i2c_client device for the dsi driver to use. Is my understanding correct?
Correct. That's kind of similar to the way an HDMI encoder driver would use an I2C adapter to query EDID. The i2c_client device would be a means for the DSI driver to access the control interface.
Okay.
Although, I'm not sure about the HDMI encoder example. An HDMI encoder would read off edid directly from the adapter(with an address specified), it wouldn't need to create an i2c client device. Therefore, an HDMI encoder wouldn't need to have a separate node for i2c in DT.
We can do without dummy dsi devices with this method. But, representing a device with 2 DT nodes seems a bit off. We'd also need to compatible strings for the same device, one for the i2c part, and the other for the dsi part.
I agree that this somewhat stretches the capabilities of device tree. Another alternative I guess would be to not have a compatible string for the I2C device at all (that's technically not valid, I guess) because we really don't need an I2C driver for the device. What we really need is a DSI driver with a means to talk over some I2C bus with some other part of its device.
I think what the driver should 'really' be is a bit subjective, and can vary based on what the buses are used for in the device. For the Toshiba chip that Jani mentioned, it tends more towards a DSI driver. Whereas, for an ADV75xx chip, it's closer to an I2C driver since only I2C can be used to configure the chip registers.
Although, I agree with the point you made about the DSI bus here:
"and the DSI interface may even be crippled, but the device is still addressable from the DSI host controller, if for nothing else than for routing the video stream."
The fact that the data on the DSI bus contains routing information (i.e, virtual channel number) always gives it some 'control' aspect.
From an adv75xx driver perspective, it should also support the ADV7511 chip, which is a RGB/DPI to HDMI encoder. For adv7511, we don't need a DSI DT node. It would be a bit inconsistent to have the bindings require both DSI and I2C nodes for one chip, and only I2C node for the other, with both chips being supported by the same driver.
Why would that be inconsistent? That sounds like the most accurate representation of the hardware to me.
Inconsistent wasn't the right term. I should have used 'uncommon' :) It's common for two chips of the same family to have a different set optional properties in DT, but it's not common for two chips of the same family to be represented by a different number of devices in DT.
I don't have an issue with the fused approach you suggested, as long as people are okay with the DT parts. Especially the part of needing 2 compatible strings in the DT.
Thanks, Archit
Thierry,
On 08/21/2015 11:39 AM, Archit Taneja wrote:
On 08/20/2015 05:18 PM, Thierry Reding wrote:
On Thu, Aug 20, 2015 at 09:46:14AM +0530, Archit Taneja wrote:
Hi Thierry, Lucas,
On 08/19/2015 08:32 PM, Thierry Reding wrote:
On Wed, Aug 19, 2015 at 04:52:24PM +0200, Lucas Stach wrote:
Am Mittwoch, den 19.08.2015, 16:34 +0200 schrieb Thierry Reding:
On Wed, Aug 19, 2015 at 04:17:08PM +0200, Lucas Stach wrote: > Hi Thierry, Archit, >
[...]
>> Perhaps a better way would be to invert this relationship. >> According to >> your proposal we'd have to have DT like this: >> >> i2c@... { >> ... >> >> dsi-device@... { >> ... >> dsi-bus = <&dsi>; >> ... >> }; >> >> ... >> }; >> >> dsi@... { >> ... >> }; >> >> Inversing the relationship would become something like this: >> >> i2c@... { >> ... >> }; >> >> dsi@... { >> ... >> >> peripheral@... { >> ... >> i2c-bus = <&i2c>; >> ... >> }; >> >> ... >> }; >> >> Both of those aren't fundamentally different, and they both have >> the >> disavantage of lacking ways to transport configuration data that >> the >> other bus needs to instantiate the dummy device (such as the reg >> property for example, denoting the I2C slave address or the DSI >> VC). >> >> So how about we create two devices in the device tree and fuse >> them at >> the driver level: >> >> i2c@... { >> ... >> >> i2cdsi: dsi-device@... { >> ... >> }; >> >> ... >> }; >> >> dsi@... { >> ... >> >> peripheral@... { >> ... >> control = <&i2cdsi>; >> ... >> }; >> >> ... >> }; >> >> This way we'll get both an I2C device and a DSI device that we >> can fully >> describe using the standard device tree bindings. At driver time >> we can >> get the I2C device from the phandle in the control property of >> the DSI >> device and use it to execute I2C transactions. >> > I don't really like to see that you are inventing yet-another-way to > handle devices connected to multiple buses. > > Devicetree is structured along the control buses, even if the > devices > are connected to multiple buses, in the DT they are always > children of > the bus that is used to control their registers from the CPUs > perspective. So a DSI encoder that is controlled through i2c is > clearly > a child of the i2c master controller and only of that one.
I think that's a flawed interpretation of what's going on here. The device in fact has two interfaces: one is I2C, the other is DSI. In my opinion that's reason enough to represent it as two logical devices.
Does it really have 2 control interfaces that are used at the same time? Or is the DSI connection a passive data bus if the register control happens through i2c?
The interfaces may not be used at the same time, and the DSI interface may even be crippled, but the device is still addressable from the DSI host controller, if for nothing else than for routing the video stream.
> If you need to model connections between devices that are not > reflected > through the control bus hierarchy you should really consider > using the > standardized of-graph bindings. > (Documentation/devicetree/bindings/graph.txt)
The problem is that the original proposal would instantiate a dummy device, so it wouldn't be represented in DT at all. So unless you do add two logical devices to DT (one for each bus interface), you don't have anything to glue together with an OF graph.
I see that the having dummy device is the least desirable solution. But if there is only one control bus to the device I think it should be one device sitting beneath the control bus.
You can then use of-graph to model the data path between the DSI encoder and device.
But you will be needing a device below the DSI host controller to represent that endpoint of the connection. The DSI host controller itself is in no way connected to the I2C adapter. You would have to add some sort of quirk to the DSI controller binding to allow it to
Thanks for the review.
I implemented this to support ADV7533 DSI to HDMI encoder chip, which has a DSI video bus and an i2c control bus.
There weren't any quirks as such in the device tree when I tried to implement this. The DT seems to manage fine without a node corresponding to a mipi_dsi_device:
i2c_adap@.. { adv7533@.. {
port { adv_in: endpoint { remote-endpoint = <&dsi_out>; }; }; };
};
dsi_host@.. { ... ...
port { dsi_out: endpoint { remote-endpoint = <&adv_in>; } };
};
It's the i2c driver's job to parse the graph and retrieve the phandle to the dsi host. Using this, it can proceed with registering itself to this host using the new dsi funcs. This patch does the same for the adv7533 i2c driver:
http://www.spinics.net/lists/dri-devel/msg86840.html
hook up with a control endpoint. And then you'll need more quirks to describe what kind of DSI device this is.
Could you explain what you meant by this? I.e. describing the kind of DSI device?
Describing the number of lanes, specifying the virtual channel, mode flags, etc. You could probably set the number of lanes and mode flags via the I2C driver, but especially the virtual channel cannot be set because it isn't known to the I2C DT branch of the device.
I agree with the VC part. It could be a DT entry within the i2c client node, but that does make it seem like a quirk. The 'reg' way under the DSI host is definitely better to populate the virtual channel.
The dsi device created isn't really a dummy device as such. It's dummy in the sense that there isn't a real dsi driver associated with it. The dsi device is still used to attach to a mipi dsi host, the way normal dsi devices do.
I understand, but I don't see why it has to be instantiated by the I2C driver, that's what I find backwards. There is already a standard way for instantiating DSI devices, why not use it?
I assumed we could either represent the device using an i2c driver, or dsi, but not both. Hence, I came up with this approach.
On the other hand if you properly instantiate the DSI device you can easily write a driver for it, and the driver will set up the correct properties as implied by the compatible string. Once you have that you can easily hook it up to the I2C control interface in whatever way you like, be that an OF graph or just a simple unidirectional link by phandle.
With the fused approach you suggested, we would have 2 drivers: one i2c and the other dsi. The i2c client driver would be more or less minimal, preparing an i2c_client device for the dsi driver to use. Is my understanding correct?
Correct. That's kind of similar to the way an HDMI encoder driver would use an I2C adapter to query EDID. The i2c_client device would be a means for the DSI driver to access the control interface.
Okay.
Although, I'm not sure about the HDMI encoder example. An HDMI encoder would read off edid directly from the adapter(with an address specified), it wouldn't need to create an i2c client device. Therefore, an HDMI encoder wouldn't need to have a separate node for i2c in DT.
We can do without dummy dsi devices with this method. But, representing a device with 2 DT nodes seems a bit off. We'd also need to compatible strings for the same device, one for the i2c part, and the other for the dsi part.
I agree that this somewhat stretches the capabilities of device tree. Another alternative I guess would be to not have a compatible string for the I2C device at all (that's technically not valid, I guess) because we really don't need an I2C driver for the device. What we really need is a DSI driver with a means to talk over some I2C bus with some other part of its device.
I think what the driver should 'really' be is a bit subjective, and can vary based on what the buses are used for in the device. For the Toshiba chip that Jani mentioned, it tends more towards a DSI driver. Whereas, for an ADV75xx chip, it's closer to an I2C driver since only I2C can be used to configure the chip registers.
Although, I agree with the point you made about the DSI bus here:
"and the DSI interface may even be crippled, but the device is still addressable from the DSI host controller, if for nothing else than for routing the video stream."
The fact that the data on the DSI bus contains routing information (i.e, virtual channel number) always gives it some 'control' aspect.
From an adv75xx driver perspective, it should also support the ADV7511 chip, which is a RGB/DPI to HDMI encoder. For adv7511, we don't need a DSI DT node. It would be a bit inconsistent to have the bindings require both DSI and I2C nodes for one chip, and only I2C node for the other, with both chips being supported by the same driver.
Why would that be inconsistent? That sounds like the most accurate representation of the hardware to me.
Inconsistent wasn't the right term. I should have used 'uncommon' :) It's common for two chips of the same family to have a different set optional properties in DT, but it's not common for two chips of the same family to be represented by a different number of devices in DT.
I don't have an issue with the fused approach you suggested, as long as people are okay with the DT parts. Especially the part of needing 2 compatible strings in the DT.
I implemented the ADV7533 driver with the approach you suggested above (2 drivers for 2 different components of the chip). I posted it out just a while back (with you in loop).
The DT node with this apporach would look like this:
https://github.com/boddob/linux/blob/c24cbf63a6998d00095c10122ce5e37b764c7db...
The main irritant with the '2 driver' approach is that we need to share the per-device driver data with them. For ADV7533, I've made the i2c driver allocate driver data (struct adv7511).
The dsi driver gets the driver data in the following way:
- The i2c driver sets the driver data as its client data using i2c_set_clientdata() - Parse the i2c-control phandle to get the corresponding i2c client. - Extract the adv7511 struct by getting i2c_get_clientdata()
This way of getting the same driver data is a bit strange, but it works. For this, we do need to ensure that the dsi driver defers as long as the i2c driver isn't probed.
I've now implemented both approaches for the driver. The first using a dummy dsi device, and this one using 2 drivers (with both being represented in DT). The advantage of the latter is that we don't need to create any dummy device stuff, the disadvantage is that DT is a bit uncommon.
Can we now come to a conclusion on what approach is better?
Thanks, Archit
On 09/07/2015 01:46 PM, Archit Taneja wrote:
Thierry,
On 08/21/2015 11:39 AM, Archit Taneja wrote:
On 08/20/2015 05:18 PM, Thierry Reding wrote:
On Thu, Aug 20, 2015 at 09:46:14AM +0530, Archit Taneja wrote:
Hi Thierry, Lucas,
On 08/19/2015 08:32 PM, Thierry Reding wrote:
On Wed, Aug 19, 2015 at 04:52:24PM +0200, Lucas Stach wrote:
Am Mittwoch, den 19.08.2015, 16:34 +0200 schrieb Thierry Reding: > On Wed, Aug 19, 2015 at 04:17:08PM +0200, Lucas Stach wrote: >> Hi Thierry, Archit, >> [...] >>> Perhaps a better way would be to invert this relationship. >>> According to >>> your proposal we'd have to have DT like this: >>> >>> i2c@... { >>> ... >>> >>> dsi-device@... { >>> ... >>> dsi-bus = <&dsi>; >>> ... >>> }; >>> >>> ... >>> }; >>> >>> dsi@... { >>> ... >>> }; >>> >>> Inversing the relationship would become something like this: >>> >>> i2c@... { >>> ... >>> }; >>> >>> dsi@... { >>> ... >>> >>> peripheral@... { >>> ... >>> i2c-bus = <&i2c>; >>> ... >>> }; >>> >>> ... >>> }; >>> >>> Both of those aren't fundamentally different, and they both have >>> the >>> disavantage of lacking ways to transport configuration data that >>> the >>> other bus needs to instantiate the dummy device (such as the reg >>> property for example, denoting the I2C slave address or the DSI >>> VC). >>> >>> So how about we create two devices in the device tree and fuse >>> them at >>> the driver level: >>> >>> i2c@... { >>> ... >>> >>> i2cdsi: dsi-device@... { >>> ... >>> }; >>> >>> ... >>> }; >>> >>> dsi@... { >>> ... >>> >>> peripheral@... { >>> ... >>> control = <&i2cdsi>; >>> ... >>> }; >>> >>> ... >>> }; >>> >>> This way we'll get both an I2C device and a DSI device that we >>> can fully >>> describe using the standard device tree bindings. At driver time >>> we can >>> get the I2C device from the phandle in the control property of >>> the DSI >>> device and use it to execute I2C transactions. >>> >> I don't really like to see that you are inventing yet-another-way to >> handle devices connected to multiple buses. >> >> Devicetree is structured along the control buses, even if the >> devices >> are connected to multiple buses, in the DT they are always >> children of >> the bus that is used to control their registers from the CPUs >> perspective. So a DSI encoder that is controlled through i2c is >> clearly >> a child of the i2c master controller and only of that one. > > I think that's a flawed interpretation of what's going on here. The > device in fact has two interfaces: one is I2C, the other is DSI. > In my > opinion that's reason enough to represent it as two logical devices. > Does it really have 2 control interfaces that are used at the same time? Or is the DSI connection a passive data bus if the register control happens through i2c?
The interfaces may not be used at the same time, and the DSI interface may even be crippled, but the device is still addressable from the DSI host controller, if for nothing else than for routing the video stream.
>> If you need to model connections between devices that are not >> reflected >> through the control bus hierarchy you should really consider >> using the >> standardized of-graph bindings. >> (Documentation/devicetree/bindings/graph.txt) > > The problem is that the original proposal would instantiate a dummy > device, so it wouldn't be represented in DT at all. So unless you > do add > two logical devices to DT (one for each bus interface), you don't > have > anything to glue together with an OF graph. > I see that the having dummy device is the least desirable solution. But if there is only one control bus to the device I think it should be one device sitting beneath the control bus.
You can then use of-graph to model the data path between the DSI encoder and device.
But you will be needing a device below the DSI host controller to represent that endpoint of the connection. The DSI host controller itself is in no way connected to the I2C adapter. You would have to add some sort of quirk to the DSI controller binding to allow it to
Thanks for the review.
I implemented this to support ADV7533 DSI to HDMI encoder chip, which has a DSI video bus and an i2c control bus.
There weren't any quirks as such in the device tree when I tried to implement this. The DT seems to manage fine without a node corresponding to a mipi_dsi_device:
i2c_adap@.. { adv7533@.. {
port { adv_in: endpoint { remote-endpoint = <&dsi_out>; }; }; };
};
dsi_host@.. { ... ...
port { dsi_out: endpoint { remote-endpoint = <&adv_in>; } };
};
It's the i2c driver's job to parse the graph and retrieve the phandle to the dsi host. Using this, it can proceed with registering itself to this host using the new dsi funcs. This patch does the same for the adv7533 i2c driver:
http://www.spinics.net/lists/dri-devel/msg86840.html
hook up with a control endpoint. And then you'll need more quirks to describe what kind of DSI device this is.
Could you explain what you meant by this? I.e. describing the kind of DSI device?
Describing the number of lanes, specifying the virtual channel, mode flags, etc. You could probably set the number of lanes and mode flags via the I2C driver, but especially the virtual channel cannot be set because it isn't known to the I2C DT branch of the device.
I agree with the VC part. It could be a DT entry within the i2c client node, but that does make it seem like a quirk. The 'reg' way under the DSI host is definitely better to populate the virtual channel.
The dsi device created isn't really a dummy device as such. It's dummy in the sense that there isn't a real dsi driver associated with it. The dsi device is still used to attach to a mipi dsi host, the way normal dsi devices do.
I understand, but I don't see why it has to be instantiated by the I2C driver, that's what I find backwards. There is already a standard way for instantiating DSI devices, why not use it?
I assumed we could either represent the device using an i2c driver, or dsi, but not both. Hence, I came up with this approach.
On the other hand if you properly instantiate the DSI device you can easily write a driver for it, and the driver will set up the correct properties as implied by the compatible string. Once you have that you can easily hook it up to the I2C control interface in whatever way you like, be that an OF graph or just a simple unidirectional link by phandle.
With the fused approach you suggested, we would have 2 drivers: one i2c and the other dsi. The i2c client driver would be more or less minimal, preparing an i2c_client device for the dsi driver to use. Is my understanding correct?
Correct. That's kind of similar to the way an HDMI encoder driver would use an I2C adapter to query EDID. The i2c_client device would be a means for the DSI driver to access the control interface.
Okay.
Although, I'm not sure about the HDMI encoder example. An HDMI encoder would read off edid directly from the adapter(with an address specified), it wouldn't need to create an i2c client device. Therefore, an HDMI encoder wouldn't need to have a separate node for i2c in DT.
We can do without dummy dsi devices with this method. But, representing a device with 2 DT nodes seems a bit off. We'd also need to compatible strings for the same device, one for the i2c part, and the other for the dsi part.
I agree that this somewhat stretches the capabilities of device tree. Another alternative I guess would be to not have a compatible string for the I2C device at all (that's technically not valid, I guess) because we really don't need an I2C driver for the device. What we really need is a DSI driver with a means to talk over some I2C bus with some other part of its device.
I think what the driver should 'really' be is a bit subjective, and can vary based on what the buses are used for in the device. For the Toshiba chip that Jani mentioned, it tends more towards a DSI driver. Whereas, for an ADV75xx chip, it's closer to an I2C driver since only I2C can be used to configure the chip registers.
Although, I agree with the point you made about the DSI bus here:
"and the DSI interface may even be crippled, but the device is still addressable from the DSI host controller, if for nothing else than for routing the video stream."
The fact that the data on the DSI bus contains routing information (i.e, virtual channel number) always gives it some 'control' aspect.
From an adv75xx driver perspective, it should also support the ADV7511 chip, which is a RGB/DPI to HDMI encoder. For adv7511, we don't need a DSI DT node. It would be a bit inconsistent to have the bindings require both DSI and I2C nodes for one chip, and only I2C node for the other, with both chips being supported by the same driver.
Why would that be inconsistent? That sounds like the most accurate representation of the hardware to me.
Inconsistent wasn't the right term. I should have used 'uncommon' :) It's common for two chips of the same family to have a different set optional properties in DT, but it's not common for two chips of the same family to be represented by a different number of devices in DT.
I don't have an issue with the fused approach you suggested, as long as people are okay with the DT parts. Especially the part of needing 2 compatible strings in the DT.
I implemented the ADV7533 driver with the approach you suggested above (2 drivers for 2 different components of the chip). I posted it out just a while back (with you in loop).
The DT node with this apporach would look like this:
https://github.com/boddob/linux/blob/c24cbf63a6998d00095c10122ce5e37b764c7db...
The main irritant with the '2 driver' approach is that we need to share the per-device driver data with them. For ADV7533, I've made the i2c driver allocate driver data (struct adv7511).
The dsi driver gets the driver data in the following way:
- The i2c driver sets the driver data as its client data using i2c_set_clientdata()
- Parse the i2c-control phandle to get the corresponding i2c client.
- Extract the adv7511 struct by getting i2c_get_clientdata()
This way of getting the same driver data is a bit strange, but it works. For this, we do need to ensure that the dsi driver defers as long as the i2c driver isn't probed.
I've now implemented both approaches for the driver. The first using a dummy dsi device, and this one using 2 drivers (with both being represented in DT). The advantage of the latter is that we don't need to create any dummy device stuff, the disadvantage is that DT is a bit uncommon.
Can we now come to a conclusion on what approach is better?
DSI by design is data bus which can be used additionally as a control bus, but in this particular case it is purely data bus. So of-graph bindings seem to be better choice. As already Lucas Stach said DT hierarchy should describe control buses and of-graph bindings should describe data bus. Argument that hw has two interfaces does not seem to be valid here - it has only one control interface. The other one is only for data, representing every data interface using DT hierarchy would lead to inflation of pseudo devices.
On the other side I do not see dummy device approach ideal solution, I guess lightweight framework providing DSI hosts detached from Linux device model could work better here. The only problem here is that it should coexist somehow with dsi bus used to control devices. Anyway implementing it shouldn't be hard, question is if it would be eventually accepted :) I guess we can live for now with dummy devs.
Summarizing I would prefer version with dummy devices, as it seems more compatible with DT design.
Regards Andrzej
Thanks, Archit
On 09/08/2015 03:57 PM, Andrzej Hajda wrote:
On 09/07/2015 01:46 PM, Archit Taneja wrote:
Thierry,
On 08/21/2015 11:39 AM, Archit Taneja wrote:
On 08/20/2015 05:18 PM, Thierry Reding wrote:
On Thu, Aug 20, 2015 at 09:46:14AM +0530, Archit Taneja wrote:
Hi Thierry, Lucas,
On 08/19/2015 08:32 PM, Thierry Reding wrote:
On Wed, Aug 19, 2015 at 04:52:24PM +0200, Lucas Stach wrote: > Am Mittwoch, den 19.08.2015, 16:34 +0200 schrieb Thierry Reding: >> On Wed, Aug 19, 2015 at 04:17:08PM +0200, Lucas Stach wrote: >>> Hi Thierry, Archit, >>> > [...] >>>> Perhaps a better way would be to invert this relationship. >>>> According to >>>> your proposal we'd have to have DT like this: >>>> >>>> i2c@... { >>>> ... >>>> >>>> dsi-device@... { >>>> ... >>>> dsi-bus = <&dsi>; >>>> ... >>>> }; >>>> >>>> ... >>>> }; >>>> >>>> dsi@... { >>>> ... >>>> }; >>>> >>>> Inversing the relationship would become something like this: >>>> >>>> i2c@... { >>>> ... >>>> }; >>>> >>>> dsi@... { >>>> ... >>>> >>>> peripheral@... { >>>> ... >>>> i2c-bus = <&i2c>; >>>> ... >>>> }; >>>> >>>> ... >>>> }; >>>> >>>> Both of those aren't fundamentally different, and they both have >>>> the >>>> disavantage of lacking ways to transport configuration data that >>>> the >>>> other bus needs to instantiate the dummy device (such as the reg >>>> property for example, denoting the I2C slave address or the DSI >>>> VC). >>>> >>>> So how about we create two devices in the device tree and fuse >>>> them at >>>> the driver level: >>>> >>>> i2c@... { >>>> ... >>>> >>>> i2cdsi: dsi-device@... { >>>> ... >>>> }; >>>> >>>> ... >>>> }; >>>> >>>> dsi@... { >>>> ... >>>> >>>> peripheral@... { >>>> ... >>>> control = <&i2cdsi>; >>>> ... >>>> }; >>>> >>>> ... >>>> }; >>>> >>>> This way we'll get both an I2C device and a DSI device that we >>>> can fully >>>> describe using the standard device tree bindings. At driver time >>>> we can >>>> get the I2C device from the phandle in the control property of >>>> the DSI >>>> device and use it to execute I2C transactions. >>>> >>> I don't really like to see that you are inventing yet-another-way to >>> handle devices connected to multiple buses. >>> >>> Devicetree is structured along the control buses, even if the >>> devices >>> are connected to multiple buses, in the DT they are always >>> children of >>> the bus that is used to control their registers from the CPUs >>> perspective. So a DSI encoder that is controlled through i2c is >>> clearly >>> a child of the i2c master controller and only of that one. >> >> I think that's a flawed interpretation of what's going on here. The >> device in fact has two interfaces: one is I2C, the other is DSI. >> In my >> opinion that's reason enough to represent it as two logical devices. >> > Does it really have 2 control interfaces that are used at the same > time? > Or is the DSI connection a passive data bus if the register control > happens through i2c?
The interfaces may not be used at the same time, and the DSI interface may even be crippled, but the device is still addressable from the DSI host controller, if for nothing else than for routing the video stream.
>>> If you need to model connections between devices that are not >>> reflected >>> through the control bus hierarchy you should really consider >>> using the >>> standardized of-graph bindings. >>> (Documentation/devicetree/bindings/graph.txt) >> >> The problem is that the original proposal would instantiate a dummy >> device, so it wouldn't be represented in DT at all. So unless you >> do add >> two logical devices to DT (one for each bus interface), you don't >> have >> anything to glue together with an OF graph. >> > I see that the having dummy device is the least desirable solution. > But > if there is only one control bus to the device I think it should be > one > device sitting beneath the control bus. > > You can then use of-graph to model the data path between the DSI > encoder > and device.
But you will be needing a device below the DSI host controller to represent that endpoint of the connection. The DSI host controller itself is in no way connected to the I2C adapter. You would have to add some sort of quirk to the DSI controller binding to allow it to
Thanks for the review.
I implemented this to support ADV7533 DSI to HDMI encoder chip, which has a DSI video bus and an i2c control bus.
There weren't any quirks as such in the device tree when I tried to implement this. The DT seems to manage fine without a node corresponding to a mipi_dsi_device:
i2c_adap@.. { adv7533@.. {
port { adv_in: endpoint { remote-endpoint = <&dsi_out>; }; }; };
};
dsi_host@.. { ... ...
port { dsi_out: endpoint { remote-endpoint = <&adv_in>; } };
};
It's the i2c driver's job to parse the graph and retrieve the phandle to the dsi host. Using this, it can proceed with registering itself to this host using the new dsi funcs. This patch does the same for the adv7533 i2c driver:
http://www.spinics.net/lists/dri-devel/msg86840.html
hook up with a control endpoint. And then you'll need more quirks to describe what kind of DSI device this is.
Could you explain what you meant by this? I.e. describing the kind of DSI device?
Describing the number of lanes, specifying the virtual channel, mode flags, etc. You could probably set the number of lanes and mode flags via the I2C driver, but especially the virtual channel cannot be set because it isn't known to the I2C DT branch of the device.
I agree with the VC part. It could be a DT entry within the i2c client node, but that does make it seem like a quirk. The 'reg' way under the DSI host is definitely better to populate the virtual channel.
The dsi device created isn't really a dummy device as such. It's dummy in the sense that there isn't a real dsi driver associated with it. The dsi device is still used to attach to a mipi dsi host, the way normal dsi devices do.
I understand, but I don't see why it has to be instantiated by the I2C driver, that's what I find backwards. There is already a standard way for instantiating DSI devices, why not use it?
I assumed we could either represent the device using an i2c driver, or dsi, but not both. Hence, I came up with this approach.
On the other hand if you properly instantiate the DSI device you can easily write a driver for it, and the driver will set up the correct properties as implied by the compatible string. Once you have that you can easily hook it up to the I2C control interface in whatever way you like, be that an OF graph or just a simple unidirectional link by phandle.
With the fused approach you suggested, we would have 2 drivers: one i2c and the other dsi. The i2c client driver would be more or less minimal, preparing an i2c_client device for the dsi driver to use. Is my understanding correct?
Correct. That's kind of similar to the way an HDMI encoder driver would use an I2C adapter to query EDID. The i2c_client device would be a means for the DSI driver to access the control interface.
Okay.
Although, I'm not sure about the HDMI encoder example. An HDMI encoder would read off edid directly from the adapter(with an address specified), it wouldn't need to create an i2c client device. Therefore, an HDMI encoder wouldn't need to have a separate node for i2c in DT.
We can do without dummy dsi devices with this method. But, representing a device with 2 DT nodes seems a bit off. We'd also need to compatible strings for the same device, one for the i2c part, and the other for the dsi part.
I agree that this somewhat stretches the capabilities of device tree. Another alternative I guess would be to not have a compatible string for the I2C device at all (that's technically not valid, I guess) because we really don't need an I2C driver for the device. What we really need is a DSI driver with a means to talk over some I2C bus with some other part of its device.
I think what the driver should 'really' be is a bit subjective, and can vary based on what the buses are used for in the device. For the Toshiba chip that Jani mentioned, it tends more towards a DSI driver. Whereas, for an ADV75xx chip, it's closer to an I2C driver since only I2C can be used to configure the chip registers.
Although, I agree with the point you made about the DSI bus here:
"and the DSI interface may even be crippled, but the device is still addressable from the DSI host controller, if for nothing else than for routing the video stream."
The fact that the data on the DSI bus contains routing information (i.e, virtual channel number) always gives it some 'control' aspect.
From an adv75xx driver perspective, it should also support the ADV7511 chip, which is a RGB/DPI to HDMI encoder. For adv7511, we don't need a DSI DT node. It would be a bit inconsistent to have the bindings require both DSI and I2C nodes for one chip, and only I2C node for the other, with both chips being supported by the same driver.
Why would that be inconsistent? That sounds like the most accurate representation of the hardware to me.
Inconsistent wasn't the right term. I should have used 'uncommon' :) It's common for two chips of the same family to have a different set optional properties in DT, but it's not common for two chips of the same family to be represented by a different number of devices in DT.
I don't have an issue with the fused approach you suggested, as long as people are okay with the DT parts. Especially the part of needing 2 compatible strings in the DT.
I implemented the ADV7533 driver with the approach you suggested above (2 drivers for 2 different components of the chip). I posted it out just a while back (with you in loop).
The DT node with this apporach would look like this:
https://github.com/boddob/linux/blob/c24cbf63a6998d00095c10122ce5e37b764c7db...
The main irritant with the '2 driver' approach is that we need to share the per-device driver data with them. For ADV7533, I've made the i2c driver allocate driver data (struct adv7511).
The dsi driver gets the driver data in the following way:
- The i2c driver sets the driver data as its client data using i2c_set_clientdata()
- Parse the i2c-control phandle to get the corresponding i2c client.
- Extract the adv7511 struct by getting i2c_get_clientdata()
This way of getting the same driver data is a bit strange, but it works. For this, we do need to ensure that the dsi driver defers as long as the i2c driver isn't probed.
I've now implemented both approaches for the driver. The first using a dummy dsi device, and this one using 2 drivers (with both being represented in DT). The advantage of the latter is that we don't need to create any dummy device stuff, the disadvantage is that DT is a bit uncommon.
Can we now come to a conclusion on what approach is better?
DSI by design is data bus which can be used additionally as a control bus, but in this particular case it is purely data bus. So of-graph bindings seem to be better choice. As already Lucas Stach said DT hierarchy should describe control buses and of-graph bindings should describe data bus. Argument that hw has two interfaces does not seem to be valid here - it has only one control interface. The other one is only for data, representing every data interface using DT hierarchy would lead to inflation of pseudo devices.
On the other side I do not see dummy device approach ideal solution, I guess lightweight framework providing DSI hosts detached from Linux device model could work better here. The only problem here is that it should coexist somehow with dsi bus used to control devices. Anyway implementing it shouldn't be hard, question is if it would be eventually accepted :) I guess we can live for now with dummy devs.
Summarizing I would prefer version with dummy devices, as it seems more compatible with DT design.
Thanks for the feedback. I'll spin a newer version of the dummy dsi dev patches after waiting for some more comments.
Archit
-- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Thu, Sep 10, 2015 at 11:45:35AM +0530, Archit Taneja wrote:
On 09/08/2015 03:57 PM, Andrzej Hajda wrote:
On 09/07/2015 01:46 PM, Archit Taneja wrote:
Thierry,
On 08/21/2015 11:39 AM, Archit Taneja wrote:
On 08/20/2015 05:18 PM, Thierry Reding wrote:
On Thu, Aug 20, 2015 at 09:46:14AM +0530, Archit Taneja wrote:
Hi Thierry, Lucas,
On 08/19/2015 08:32 PM, Thierry Reding wrote: >On Wed, Aug 19, 2015 at 04:52:24PM +0200, Lucas Stach wrote: >>Am Mittwoch, den 19.08.2015, 16:34 +0200 schrieb Thierry Reding: >>>On Wed, Aug 19, 2015 at 04:17:08PM +0200, Lucas Stach wrote: >>>>Hi Thierry, Archit, >>>> >>[...] >>>>>Perhaps a better way would be to invert this relationship. >>>>>According to >>>>>your proposal we'd have to have DT like this: >>>>> >>>>> i2c@... { >>>>> ... >>>>> >>>>> dsi-device@... { >>>>> ... >>>>> dsi-bus = <&dsi>; >>>>> ... >>>>> }; >>>>> >>>>> ... >>>>> }; >>>>> >>>>> dsi@... { >>>>> ... >>>>> }; >>>>> >>>>>Inversing the relationship would become something like this: >>>>> >>>>> i2c@... { >>>>> ... >>>>> }; >>>>> >>>>> dsi@... { >>>>> ... >>>>> >>>>> peripheral@... { >>>>> ... >>>>> i2c-bus = <&i2c>; >>>>> ... >>>>> }; >>>>> >>>>> ... >>>>> }; >>>>> >>>>>Both of those aren't fundamentally different, and they both have >>>>>the >>>>>disavantage of lacking ways to transport configuration data that >>>>>the >>>>>other bus needs to instantiate the dummy device (such as the reg >>>>>property for example, denoting the I2C slave address or the DSI >>>>>VC). >>>>> >>>>>So how about we create two devices in the device tree and fuse >>>>>them at >>>>>the driver level: >>>>> >>>>> i2c@... { >>>>> ... >>>>> >>>>> i2cdsi: dsi-device@... { >>>>> ... >>>>> }; >>>>> >>>>> ... >>>>> }; >>>>> >>>>> dsi@... { >>>>> ... >>>>> >>>>> peripheral@... { >>>>> ... >>>>> control = <&i2cdsi>; >>>>> ... >>>>> }; >>>>> >>>>> ... >>>>> }; >>>>> >>>>>This way we'll get both an I2C device and a DSI device that we >>>>>can fully >>>>>describe using the standard device tree bindings. At driver time >>>>>we can >>>>>get the I2C device from the phandle in the control property of >>>>>the DSI >>>>>device and use it to execute I2C transactions. >>>>> >>>>I don't really like to see that you are inventing yet-another-way to >>>>handle devices connected to multiple buses. >>>> >>>>Devicetree is structured along the control buses, even if the >>>>devices >>>>are connected to multiple buses, in the DT they are always >>>>children of >>>>the bus that is used to control their registers from the CPUs >>>>perspective. So a DSI encoder that is controlled through i2c is >>>>clearly >>>>a child of the i2c master controller and only of that one. >>> >>>I think that's a flawed interpretation of what's going on here. The >>>device in fact has two interfaces: one is I2C, the other is DSI. >>>In my >>>opinion that's reason enough to represent it as two logical devices. >>> >>Does it really have 2 control interfaces that are used at the same >>time? >>Or is the DSI connection a passive data bus if the register control >>happens through i2c? > >The interfaces may not be used at the same time, and the DSI interface >may even be crippled, but the device is still addressable from the DSI >host controller, if for nothing else than for routing the video stream. > >>>>If you need to model connections between devices that are not >>>>reflected >>>>through the control bus hierarchy you should really consider >>>>using the >>>>standardized of-graph bindings. >>>>(Documentation/devicetree/bindings/graph.txt) >>> >>>The problem is that the original proposal would instantiate a dummy >>>device, so it wouldn't be represented in DT at all. So unless you >>>do add >>>two logical devices to DT (one for each bus interface), you don't >>>have >>>anything to glue together with an OF graph. >>> >>I see that the having dummy device is the least desirable solution. >>But >>if there is only one control bus to the device I think it should be >>one >>device sitting beneath the control bus. >> >>You can then use of-graph to model the data path between the DSI >>encoder >>and device. > >But you will be needing a device below the DSI host controller to >represent that endpoint of the connection. The DSI host controller >itself is in no way connected to the I2C adapter. You would have to >add some sort of quirk to the DSI controller binding to allow it to
Thanks for the review.
I implemented this to support ADV7533 DSI to HDMI encoder chip, which has a DSI video bus and an i2c control bus.
There weren't any quirks as such in the device tree when I tried to implement this. The DT seems to manage fine without a node corresponding to a mipi_dsi_device:
i2c_adap@.. { adv7533@.. {
port { adv_in: endpoint { remote-endpoint = <&dsi_out>; }; }; };
};
dsi_host@.. { ... ...
port { dsi_out: endpoint { remote-endpoint = <&adv_in>; } };
};
It's the i2c driver's job to parse the graph and retrieve the phandle to the dsi host. Using this, it can proceed with registering itself to this host using the new dsi funcs. This patch does the same for the adv7533 i2c driver:
http://www.spinics.net/lists/dri-devel/msg86840.html
>hook up with a control endpoint. And then you'll need more quirks >to describe what kind of DSI device this is.
Could you explain what you meant by this? I.e. describing the kind of DSI device?
Describing the number of lanes, specifying the virtual channel, mode flags, etc. You could probably set the number of lanes and mode flags via the I2C driver, but especially the virtual channel cannot be set because it isn't known to the I2C DT branch of the device.
I agree with the VC part. It could be a DT entry within the i2c client node, but that does make it seem like a quirk. The 'reg' way under the DSI host is definitely better to populate the virtual channel.
The dsi device created isn't really a dummy device as such. It's dummy in the sense that there isn't a real dsi driver associated with it. The dsi device is still used to attach to a mipi dsi host, the way normal dsi devices do.
I understand, but I don't see why it has to be instantiated by the I2C driver, that's what I find backwards. There is already a standard way for instantiating DSI devices, why not use it?
I assumed we could either represent the device using an i2c driver, or dsi, but not both. Hence, I came up with this approach.
>On the other hand if you properly instantiate the DSI device you can >easily write a driver for it, and the driver will set up the correct >properties as implied by the compatible string. Once you have that you >can easily hook it up to the I2C control interface in whatever way you >like, be that an OF graph or just a simple unidirectional link by >phandle. >
With the fused approach you suggested, we would have 2 drivers: one i2c and the other dsi. The i2c client driver would be more or less minimal, preparing an i2c_client device for the dsi driver to use. Is my understanding correct?
Correct. That's kind of similar to the way an HDMI encoder driver would use an I2C adapter to query EDID. The i2c_client device would be a means for the DSI driver to access the control interface.
Okay.
Although, I'm not sure about the HDMI encoder example. An HDMI encoder would read off edid directly from the adapter(with an address specified), it wouldn't need to create an i2c client device. Therefore, an HDMI encoder wouldn't need to have a separate node for i2c in DT.
We can do without dummy dsi devices with this method. But, representing a device with 2 DT nodes seems a bit off. We'd also need to compatible strings for the same device, one for the i2c part, and the other for the dsi part.
I agree that this somewhat stretches the capabilities of device tree. Another alternative I guess would be to not have a compatible string for the I2C device at all (that's technically not valid, I guess) because we really don't need an I2C driver for the device. What we really need is a DSI driver with a means to talk over some I2C bus with some other part of its device.
I think what the driver should 'really' be is a bit subjective, and can vary based on what the buses are used for in the device. For the Toshiba chip that Jani mentioned, it tends more towards a DSI driver. Whereas, for an ADV75xx chip, it's closer to an I2C driver since only I2C can be used to configure the chip registers.
Although, I agree with the point you made about the DSI bus here:
"and the DSI interface may even be crippled, but the device is still addressable from the DSI host controller, if for nothing else than for routing the video stream."
The fact that the data on the DSI bus contains routing information (i.e, virtual channel number) always gives it some 'control' aspect.
From an adv75xx driver perspective, it should also support the ADV7511 chip, which is a RGB/DPI to HDMI encoder. For adv7511, we don't need a DSI DT node. It would be a bit inconsistent to have the bindings require both DSI and I2C nodes for one chip, and only I2C node for the other, with both chips being supported by the same driver.
Why would that be inconsistent? That sounds like the most accurate representation of the hardware to me.
Inconsistent wasn't the right term. I should have used 'uncommon' :) It's common for two chips of the same family to have a different set optional properties in DT, but it's not common for two chips of the same family to be represented by a different number of devices in DT.
I don't have an issue with the fused approach you suggested, as long as people are okay with the DT parts. Especially the part of needing 2 compatible strings in the DT.
I implemented the ADV7533 driver with the approach you suggested above (2 drivers for 2 different components of the chip). I posted it out just a while back (with you in loop).
The DT node with this apporach would look like this:
https://github.com/boddob/linux/blob/c24cbf63a6998d00095c10122ce5e37b764c7db...
The main irritant with the '2 driver' approach is that we need to share the per-device driver data with them. For ADV7533, I've made the i2c driver allocate driver data (struct adv7511).
The dsi driver gets the driver data in the following way:
- The i2c driver sets the driver data as its client data using i2c_set_clientdata()
- Parse the i2c-control phandle to get the corresponding i2c client.
- Extract the adv7511 struct by getting i2c_get_clientdata()
This way of getting the same driver data is a bit strange, but it works. For this, we do need to ensure that the dsi driver defers as long as the i2c driver isn't probed.
I've now implemented both approaches for the driver. The first using a dummy dsi device, and this one using 2 drivers (with both being represented in DT). The advantage of the latter is that we don't need to create any dummy device stuff, the disadvantage is that DT is a bit uncommon.
Can we now come to a conclusion on what approach is better?
DSI by design is data bus which can be used additionally as a control bus, but in this particular case it is purely data bus. So of-graph bindings seem to be better choice. As already Lucas Stach said DT hierarchy should describe control buses and of-graph bindings should describe data bus. Argument that hw has two interfaces does not seem to be valid here - it has only one control interface. The other one is only for data, representing every data interface using DT hierarchy would lead to inflation of pseudo devices.
On the other side I do not see dummy device approach ideal solution, I guess lightweight framework providing DSI hosts detached from Linux device model could work better here. The only problem here is that it should coexist somehow with dsi bus used to control devices. Anyway implementing it shouldn't be hard, question is if it would be eventually accepted :) I guess we can live for now with dummy devs.
Summarizing I would prefer version with dummy devices, as it seems more compatible with DT design.
Thanks for the feedback. I'll spin a newer version of the dummy dsi dev patches after waiting for some more comments.
Let's wait for someone from the device tree maintainers to comment instead of going around in circles.
Thierry
Hi Rob, Mark,
We've been trying to figure out the right way to represent a class of display encoder devices in DT.
These devices have registers that are generally configured via i2c. Once the device is configured, it takes in video data from the mipi dsi bus.
Until now, all the devices we've supported devices that can be are configured by the dsi bus itself, and hence, we've been able to represent them in DT as children under the dsi host.
For the above class of devices (using both i2c and dsi), we aren't able to conclude upon what's the better approach among the two:
1. Represent the device via 2 different nodes in DT. One would be a child under an i2c adapter, the other a child of a dsi host. We would have two device drivers, one i2c client, and the other a mipi dsi device.
2. Represent the device as an i2c client in DT. Provide an api to create "dummy" dsi devices. The i2c client driver would use this api to register a dsi device, and link itself with the dsi host.
What do you think would be the way to go here? I guess you might have faced something similar in other subsystems.
I've given a relatively brief description of the problem. There were some more nitty gritties discussed in this thread before.
Thierry, Andrzej, Lucas,
Please feel free to add your comments if I have missed out on something.
Thanks, Archit
On 09/10/2015 01:02 PM, Thierry Reding wrote:
On Thu, Sep 10, 2015 at 11:45:35AM +0530, Archit Taneja wrote:
On 09/08/2015 03:57 PM, Andrzej Hajda wrote:
On 09/07/2015 01:46 PM, Archit Taneja wrote:
Thierry,
On 08/21/2015 11:39 AM, Archit Taneja wrote:
On 08/20/2015 05:18 PM, Thierry Reding wrote:
On Thu, Aug 20, 2015 at 09:46:14AM +0530, Archit Taneja wrote: > Hi Thierry, Lucas, > > > On 08/19/2015 08:32 PM, Thierry Reding wrote: >> On Wed, Aug 19, 2015 at 04:52:24PM +0200, Lucas Stach wrote: >>> Am Mittwoch, den 19.08.2015, 16:34 +0200 schrieb Thierry Reding: >>>> On Wed, Aug 19, 2015 at 04:17:08PM +0200, Lucas Stach wrote: >>>>> Hi Thierry, Archit, >>>>> >>> [...] >>>>>> Perhaps a better way would be to invert this relationship. >>>>>> According to >>>>>> your proposal we'd have to have DT like this: >>>>>> >>>>>> i2c@... { >>>>>> ... >>>>>> >>>>>> dsi-device@... { >>>>>> ... >>>>>> dsi-bus = <&dsi>; >>>>>> ... >>>>>> }; >>>>>> >>>>>> ... >>>>>> }; >>>>>> >>>>>> dsi@... { >>>>>> ... >>>>>> }; >>>>>> >>>>>> Inversing the relationship would become something like this: >>>>>> >>>>>> i2c@... { >>>>>> ... >>>>>> }; >>>>>> >>>>>> dsi@... { >>>>>> ... >>>>>> >>>>>> peripheral@... { >>>>>> ... >>>>>> i2c-bus = <&i2c>; >>>>>> ... >>>>>> }; >>>>>> >>>>>> ... >>>>>> }; >>>>>> >>>>>> Both of those aren't fundamentally different, and they both have >>>>>> the >>>>>> disavantage of lacking ways to transport configuration data that >>>>>> the >>>>>> other bus needs to instantiate the dummy device (such as the reg >>>>>> property for example, denoting the I2C slave address or the DSI >>>>>> VC). >>>>>> >>>>>> So how about we create two devices in the device tree and fuse >>>>>> them at >>>>>> the driver level: >>>>>> >>>>>> i2c@... { >>>>>> ... >>>>>> >>>>>> i2cdsi: dsi-device@... { >>>>>> ... >>>>>> }; >>>>>> >>>>>> ... >>>>>> }; >>>>>> >>>>>> dsi@... { >>>>>> ... >>>>>> >>>>>> peripheral@... { >>>>>> ... >>>>>> control = <&i2cdsi>; >>>>>> ... >>>>>> }; >>>>>> >>>>>> ... >>>>>> }; >>>>>> >>>>>> This way we'll get both an I2C device and a DSI device that we >>>>>> can fully >>>>>> describe using the standard device tree bindings. At driver time >>>>>> we can >>>>>> get the I2C device from the phandle in the control property of >>>>>> the DSI >>>>>> device and use it to execute I2C transactions. >>>>>> >>>>> I don't really like to see that you are inventing yet-another-way to >>>>> handle devices connected to multiple buses. >>>>> >>>>> Devicetree is structured along the control buses, even if the >>>>> devices >>>>> are connected to multiple buses, in the DT they are always >>>>> children of >>>>> the bus that is used to control their registers from the CPUs >>>>> perspective. So a DSI encoder that is controlled through i2c is >>>>> clearly >>>>> a child of the i2c master controller and only of that one. >>>> >>>> I think that's a flawed interpretation of what's going on here. The >>>> device in fact has two interfaces: one is I2C, the other is DSI. >>>> In my >>>> opinion that's reason enough to represent it as two logical devices. >>>> >>> Does it really have 2 control interfaces that are used at the same >>> time? >>> Or is the DSI connection a passive data bus if the register control >>> happens through i2c? >> >> The interfaces may not be used at the same time, and the DSI interface >> may even be crippled, but the device is still addressable from the DSI >> host controller, if for nothing else than for routing the video stream. >> >>>>> If you need to model connections between devices that are not >>>>> reflected >>>>> through the control bus hierarchy you should really consider >>>>> using the >>>>> standardized of-graph bindings. >>>>> (Documentation/devicetree/bindings/graph.txt) >>>> >>>> The problem is that the original proposal would instantiate a dummy >>>> device, so it wouldn't be represented in DT at all. So unless you >>>> do add >>>> two logical devices to DT (one for each bus interface), you don't >>>> have >>>> anything to glue together with an OF graph. >>>> >>> I see that the having dummy device is the least desirable solution. >>> But >>> if there is only one control bus to the device I think it should be >>> one >>> device sitting beneath the control bus. >>> >>> You can then use of-graph to model the data path between the DSI >>> encoder >>> and device. >> >> But you will be needing a device below the DSI host controller to >> represent that endpoint of the connection. The DSI host controller >> itself is in no way connected to the I2C adapter. You would have to >> add some sort of quirk to the DSI controller binding to allow it to > > Thanks for the review. > > I implemented this to support ADV7533 DSI to HDMI encoder chip, which > has a DSI video bus and an i2c control bus. > > There weren't any quirks as such in the device tree when I tried to > implement this. The DT seems to manage fine without a node > corresponding to a mipi_dsi_device: > > i2c_adap@.. { > adv7533@.. { > > port { > adv_in: endpoint { > remote-endpoint = <&dsi_out>; > }; > }; > }; > }; > > dsi_host@.. { > ... > ... > > port { > dsi_out: endpoint { > remote-endpoint = <&adv_in>; > } > }; > }; > > It's the i2c driver's job to parse the graph and retrieve the > phandle to the dsi host. Using this, it can proceed with > registering itself to this host using the new dsi funcs. This > patch does the same for the adv7533 i2c driver: > > http://www.spinics.net/lists/dri-devel/msg86840.html > >> hook up with a control endpoint. And then you'll need more quirks >> to describe what kind of DSI device this is. > > Could you explain what you meant by this? I.e. describing the kind > of DSI device?
Describing the number of lanes, specifying the virtual channel, mode flags, etc. You could probably set the number of lanes and mode flags via the I2C driver, but especially the virtual channel cannot be set because it isn't known to the I2C DT branch of the device.
I agree with the VC part. It could be a DT entry within the i2c client node, but that does make it seem like a quirk. The 'reg' way under the DSI host is definitely better to populate the virtual channel.
> The dsi device created isn't really a dummy device as such. It's > dummy in the sense that there isn't a real dsi driver associated > with it. The dsi device is still used to attach to a mipi dsi host, > the way normal dsi devices do.
I understand, but I don't see why it has to be instantiated by the I2C driver, that's what I find backwards. There is already a standard way for instantiating DSI devices, why not use it?
I assumed we could either represent the device using an i2c driver, or dsi, but not both. Hence, I came up with this approach.
>> On the other hand if you properly instantiate the DSI device you can >> easily write a driver for it, and the driver will set up the correct >> properties as implied by the compatible string. Once you have that you >> can easily hook it up to the I2C control interface in whatever way you >> like, be that an OF graph or just a simple unidirectional link by >> phandle. >> > > With the fused approach you suggested, we would have 2 drivers: one i2c > and the other dsi. The i2c client driver would be more or less minimal, > preparing an i2c_client device for the dsi driver to use. Is my > understanding correct?
Correct. That's kind of similar to the way an HDMI encoder driver would use an I2C adapter to query EDID. The i2c_client device would be a means for the DSI driver to access the control interface.
Okay.
Although, I'm not sure about the HDMI encoder example. An HDMI encoder would read off edid directly from the adapter(with an address specified), it wouldn't need to create an i2c client device. Therefore, an HDMI encoder wouldn't need to have a separate node for i2c in DT.
> We can do without dummy dsi devices with this method. But, representing > a device with 2 DT nodes seems a bit off. We'd also need to compatible > strings for the same device, one for the i2c part, and the other for > the dsi part.
I agree that this somewhat stretches the capabilities of device tree. Another alternative I guess would be to not have a compatible string for the I2C device at all (that's technically not valid, I guess) because we really don't need an I2C driver for the device. What we really need is a DSI driver with a means to talk over some I2C bus with some other part of its device.
I think what the driver should 'really' be is a bit subjective, and can vary based on what the buses are used for in the device. For the Toshiba chip that Jani mentioned, it tends more towards a DSI driver. Whereas, for an ADV75xx chip, it's closer to an I2C driver since only I2C can be used to configure the chip registers.
Although, I agree with the point you made about the DSI bus here:
"and the DSI interface may even be crippled, but the device is still addressable from the DSI host controller, if for nothing else than for routing the video stream."
The fact that the data on the DSI bus contains routing information (i.e, virtual channel number) always gives it some 'control' aspect.
> From an adv75xx driver perspective, it should also support the ADV7511 > chip, which is a RGB/DPI to HDMI encoder. For adv7511, we don't need a > DSI DT node. It would be a bit inconsistent to have the bindings > require both DSI and I2C nodes for one chip, and only I2C node for the > other, with both chips being supported by the same driver.
Why would that be inconsistent? That sounds like the most accurate representation of the hardware to me.
Inconsistent wasn't the right term. I should have used 'uncommon' :) It's common for two chips of the same family to have a different set optional properties in DT, but it's not common for two chips of the same family to be represented by a different number of devices in DT.
I don't have an issue with the fused approach you suggested, as long as people are okay with the DT parts. Especially the part of needing 2 compatible strings in the DT.
I implemented the ADV7533 driver with the approach you suggested above (2 drivers for 2 different components of the chip). I posted it out just a while back (with you in loop).
The DT node with this apporach would look like this:
https://github.com/boddob/linux/blob/c24cbf63a6998d00095c10122ce5e37b764c7db...
The main irritant with the '2 driver' approach is that we need to share the per-device driver data with them. For ADV7533, I've made the i2c driver allocate driver data (struct adv7511).
The dsi driver gets the driver data in the following way:
- The i2c driver sets the driver data as its client data using i2c_set_clientdata()
- Parse the i2c-control phandle to get the corresponding i2c client.
- Extract the adv7511 struct by getting i2c_get_clientdata()
This way of getting the same driver data is a bit strange, but it works. For this, we do need to ensure that the dsi driver defers as long as the i2c driver isn't probed.
I've now implemented both approaches for the driver. The first using a dummy dsi device, and this one using 2 drivers (with both being represented in DT). The advantage of the latter is that we don't need to create any dummy device stuff, the disadvantage is that DT is a bit uncommon.
Can we now come to a conclusion on what approach is better?
DSI by design is data bus which can be used additionally as a control bus, but in this particular case it is purely data bus. So of-graph bindings seem to be better choice. As already Lucas Stach said DT hierarchy should describe control buses and of-graph bindings should describe data bus. Argument that hw has two interfaces does not seem to be valid here - it has only one control interface. The other one is only for data, representing every data interface using DT hierarchy would lead to inflation of pseudo devices.
On the other side I do not see dummy device approach ideal solution, I guess lightweight framework providing DSI hosts detached from Linux device model could work better here. The only problem here is that it should coexist somehow with dsi bus used to control devices. Anyway implementing it shouldn't be hard, question is if it would be eventually accepted :) I guess we can live for now with dummy devs.
Summarizing I would prefer version with dummy devices, as it seems more compatible with DT design.
Thanks for the feedback. I'll spin a newer version of the dummy dsi dev patches after waiting for some more comments.
Let's wait for someone from the device tree maintainers to comment instead of going around in circles.
Thierry
On 09/15/2015 05:32 AM, Archit Taneja wrote:
Hi Rob, Mark,
We've been trying to figure out the right way to represent a class of display encoder devices in DT.
I've been meaning to reply on this.
These devices have registers that are generally configured via i2c. Once the device is configured, it takes in video data from the mipi dsi bus.
Until now, all the devices we've supported devices that can be are configured by the dsi bus itself, and hence, we've been able to represent them in DT as children under the dsi host.
For the above class of devices (using both i2c and dsi), we aren't able to conclude upon what's the better approach among the two:
- Represent the device via 2 different nodes in DT. One would be
a child under an i2c adapter, the other a child of a dsi host. We would have two device drivers, one i2c client, and the other a mipi dsi device.
- Represent the device as an i2c client in DT. Provide an api
to create "dummy" dsi devices. The i2c client driver would use this api to register a dsi device, and link itself with the dsi host.
What do you think would be the way to go here? I guess you might have faced something similar in other subsystems.
The closest thing I can think of are WiFi/BT combo chips that use SDIO+UART. In that case, 2 nodes makes sense as these chips are essentially 2 independent functions in a single chip and both interfaces are control interfaces (as well as data). This case is a bit different with both interfaces being tied to the same function.
So in this case, I think option 2 is the right way for the reasons already outlined in this thread. I think there needs to be more consistency in how the of-graph connections are defined with the core doing more of the graph traversing. So having an i2c device plus of-graph seems more consistent with other non-DSI cases.
The main open issue seemed to be setting the VC. At least for the ADV7533, it can be whatever you want it to be. The host and device just need to agree. I see no need for that to be in DT at least in this case. But then I'm not sure what are typical constraints for VC assignment. I'd guess that constraints are on the device side and hosts can support whatever the device wants. If so, then it can purely be up to the driver to set.
Implementation-wise, I don't think that I'd call this a dummy device. There are multiple ways for devices to get created in the driver model. DT is just one way. You are just creating the device in a different way outside of DT which is fine.
Rob
I've given a relatively brief description of the problem. There were some more nitty gritties discussed in this thread before.
Thierry, Andrzej, Lucas,
Please feel free to add your comments if I have missed out on something.
Thanks, Archit
On 09/10/2015 01:02 PM, Thierry Reding wrote:
On Thu, Sep 10, 2015 at 11:45:35AM +0530, Archit Taneja wrote:
On 09/08/2015 03:57 PM, Andrzej Hajda wrote:
On 09/07/2015 01:46 PM, Archit Taneja wrote:
Thierry,
On 08/21/2015 11:39 AM, Archit Taneja wrote:
On 08/20/2015 05:18 PM, Thierry Reding wrote: > On Thu, Aug 20, 2015 at 09:46:14AM +0530, Archit Taneja wrote: >> Hi Thierry, Lucas, >> >> >> On 08/19/2015 08:32 PM, Thierry Reding wrote: >>> On Wed, Aug 19, 2015 at 04:52:24PM +0200, Lucas Stach wrote: >>>> Am Mittwoch, den 19.08.2015, 16:34 +0200 schrieb Thierry Reding: >>>>> On Wed, Aug 19, 2015 at 04:17:08PM +0200, Lucas Stach wrote: >>>>>> Hi Thierry, Archit, >>>>>> >>>> [...] >>>>>>> Perhaps a better way would be to invert this relationship. >>>>>>> According to >>>>>>> your proposal we'd have to have DT like this: >>>>>>> >>>>>>> i2c@... { >>>>>>> ... >>>>>>> >>>>>>> dsi-device@... { >>>>>>> ... >>>>>>> dsi-bus = <&dsi>; >>>>>>> ... >>>>>>> }; >>>>>>> >>>>>>> ... >>>>>>> }; >>>>>>> >>>>>>> dsi@... { >>>>>>> ... >>>>>>> }; >>>>>>> >>>>>>> Inversing the relationship would become something like this: >>>>>>> >>>>>>> i2c@... { >>>>>>> ... >>>>>>> }; >>>>>>> >>>>>>> dsi@... { >>>>>>> ... >>>>>>> >>>>>>> peripheral@... { >>>>>>> ... >>>>>>> i2c-bus = <&i2c>; >>>>>>> ... >>>>>>> }; >>>>>>> >>>>>>> ... >>>>>>> }; >>>>>>> >>>>>>> Both of those aren't fundamentally different, and they both >>>>>>> have >>>>>>> the >>>>>>> disavantage of lacking ways to transport configuration data >>>>>>> that >>>>>>> the >>>>>>> other bus needs to instantiate the dummy device (such as >>>>>>> the reg >>>>>>> property for example, denoting the I2C slave address or the >>>>>>> DSI >>>>>>> VC). >>>>>>> >>>>>>> So how about we create two devices in the device tree and fuse >>>>>>> them at >>>>>>> the driver level: >>>>>>> >>>>>>> i2c@... { >>>>>>> ... >>>>>>> >>>>>>> i2cdsi: dsi-device@... { >>>>>>> ... >>>>>>> }; >>>>>>> >>>>>>> ... >>>>>>> }; >>>>>>> >>>>>>> dsi@... { >>>>>>> ... >>>>>>> >>>>>>> peripheral@... { >>>>>>> ... >>>>>>> control = <&i2cdsi>; >>>>>>> ... >>>>>>> }; >>>>>>> >>>>>>> ... >>>>>>> }; >>>>>>> >>>>>>> This way we'll get both an I2C device and a DSI device that we >>>>>>> can fully >>>>>>> describe using the standard device tree bindings. At driver >>>>>>> time >>>>>>> we can >>>>>>> get the I2C device from the phandle in the control property of >>>>>>> the DSI >>>>>>> device and use it to execute I2C transactions. >>>>>>> >>>>>> I don't really like to see that you are inventing >>>>>> yet-another-way to >>>>>> handle devices connected to multiple buses. >>>>>> >>>>>> Devicetree is structured along the control buses, even if the >>>>>> devices >>>>>> are connected to multiple buses, in the DT they are always >>>>>> children of >>>>>> the bus that is used to control their registers from the CPUs >>>>>> perspective. So a DSI encoder that is controlled through i2c is >>>>>> clearly >>>>>> a child of the i2c master controller and only of that one. >>>>> >>>>> I think that's a flawed interpretation of what's going on >>>>> here. The >>>>> device in fact has two interfaces: one is I2C, the other is DSI. >>>>> In my >>>>> opinion that's reason enough to represent it as two logical >>>>> devices. >>>>> >>>> Does it really have 2 control interfaces that are used at the >>>> same >>>> time? >>>> Or is the DSI connection a passive data bus if the register >>>> control >>>> happens through i2c? >>> >>> The interfaces may not be used at the same time, and the DSI >>> interface >>> may even be crippled, but the device is still addressable from >>> the DSI >>> host controller, if for nothing else than for routing the video >>> stream. >>> >>>>>> If you need to model connections between devices that are not >>>>>> reflected >>>>>> through the control bus hierarchy you should really consider >>>>>> using the >>>>>> standardized of-graph bindings. >>>>>> (Documentation/devicetree/bindings/graph.txt) >>>>> >>>>> The problem is that the original proposal would instantiate a >>>>> dummy >>>>> device, so it wouldn't be represented in DT at all. So unless >>>>> you >>>>> do add >>>>> two logical devices to DT (one for each bus interface), you >>>>> don't >>>>> have >>>>> anything to glue together with an OF graph. >>>>> >>>> I see that the having dummy device is the least desirable >>>> solution. >>>> But >>>> if there is only one control bus to the device I think it >>>> should be >>>> one >>>> device sitting beneath the control bus. >>>> >>>> You can then use of-graph to model the data path between the DSI >>>> encoder >>>> and device. >>> >>> But you will be needing a device below the DSI host controller to >>> represent that endpoint of the connection. The DSI host controller >>> itself is in no way connected to the I2C adapter. You would >>> have to >>> add some sort of quirk to the DSI controller binding to allow >>> it to >> >> Thanks for the review. >> >> I implemented this to support ADV7533 DSI to HDMI encoder chip, >> which >> has a DSI video bus and an i2c control bus. >> >> There weren't any quirks as such in the device tree when I tried to >> implement this. The DT seems to manage fine without a node >> corresponding to a mipi_dsi_device: >> >> i2c_adap@.. { >> adv7533@.. { >> >> port { >> adv_in: endpoint { >> remote-endpoint = <&dsi_out>; >> }; >> }; >> }; >> }; >> >> dsi_host@.. { >> ... >> ... >> >> port { >> dsi_out: endpoint { >> remote-endpoint = <&adv_in>; >> } >> }; >> }; >> >> It's the i2c driver's job to parse the graph and retrieve the >> phandle to the dsi host. Using this, it can proceed with >> registering itself to this host using the new dsi funcs. This >> patch does the same for the adv7533 i2c driver: >> >> http://www.spinics.net/lists/dri-devel/msg86840.html >> >>> hook up with a control endpoint. And then you'll need more quirks >>> to describe what kind of DSI device this is. >> >> Could you explain what you meant by this? I.e. describing the kind >> of DSI device? > > Describing the number of lanes, specifying the virtual channel, mode > flags, etc. You could probably set the number of lanes and mode > flags > via the I2C driver, but especially the virtual channel cannot be set > because it isn't known to the I2C DT branch of the device.
I agree with the VC part. It could be a DT entry within the i2c client node, but that does make it seem like a quirk. The 'reg' way under the DSI host is definitely better to populate the virtual channel.
> >> The dsi device created isn't really a dummy device as such. It's >> dummy in the sense that there isn't a real dsi driver associated >> with it. The dsi device is still used to attach to a mipi dsi host, >> the way normal dsi devices do. > > I understand, but I don't see why it has to be instantiated by > the I2C > driver, that's what I find backwards. There is already a standard > way > for instantiating DSI devices, why not use it?
I assumed we could either represent the device using an i2c driver, or dsi, but not both. Hence, I came up with this approach.
> >>> On the other hand if you properly instantiate the DSI device >>> you can >>> easily write a driver for it, and the driver will set up the >>> correct >>> properties as implied by the compatible string. Once you have >>> that you >>> can easily hook it up to the I2C control interface in whatever >>> way you >>> like, be that an OF graph or just a simple unidirectional link by >>> phandle. >>> >> >> With the fused approach you suggested, we would have 2 drivers: >> one i2c >> and the other dsi. The i2c client driver would be more or less >> minimal, >> preparing an i2c_client device for the dsi driver to use. Is my >> understanding correct? > > Correct. That's kind of similar to the way an HDMI encoder driver > would > use an I2C adapter to query EDID. The i2c_client device would be > a means > for the DSI driver to access the control interface.
Okay.
Although, I'm not sure about the HDMI encoder example. An HDMI encoder would read off edid directly from the adapter(with an address specified), it wouldn't need to create an i2c client device. Therefore, an HDMI encoder wouldn't need to have a separate node for i2c in DT.
> >> We can do without dummy dsi devices with this method. But, >> representing >> a device with 2 DT nodes seems a bit off. We'd also need to >> compatible >> strings for the same device, one for the i2c part, and the other >> for >> the dsi part. > > I agree that this somewhat stretches the capabilities of device > tree. > Another alternative I guess would be to not have a compatible > string for > the I2C device at all (that's technically not valid, I guess) > because we > really don't need an I2C driver for the device. What we really > need is a > DSI driver with a means to talk over some I2C bus with some other > part > of its device.
I think what the driver should 'really' be is a bit subjective, and can vary based on what the buses are used for in the device. For the Toshiba chip that Jani mentioned, it tends more towards a DSI driver. Whereas, for an ADV75xx chip, it's closer to an I2C driver since only I2C can be used to configure the chip registers.
Although, I agree with the point you made about the DSI bus here:
"and the DSI interface may even be crippled, but the device is still addressable from the DSI host controller, if for nothing else than for routing the video stream."
The fact that the data on the DSI bus contains routing information (i.e, virtual channel number) always gives it some 'control' aspect.
> >> From an adv75xx driver perspective, it should also support the >> ADV7511 >> chip, which is a RGB/DPI to HDMI encoder. For adv7511, we don't >> need a >> DSI DT node. It would be a bit inconsistent to have the bindings >> require both DSI and I2C nodes for one chip, and only I2C node >> for the >> other, with both chips being supported by the same driver. > > Why would that be inconsistent? That sounds like the most accurate > representation of the hardware to me.
Inconsistent wasn't the right term. I should have used 'uncommon' :) It's common for two chips of the same family to have a different set optional properties in DT, but it's not common for two chips of the same family to be represented by a different number of devices in DT.
I don't have an issue with the fused approach you suggested, as long as people are okay with the DT parts. Especially the part of needing 2 compatible strings in the DT.
I implemented the ADV7533 driver with the approach you suggested above (2 drivers for 2 different components of the chip). I posted it out just a while back (with you in loop).
The DT node with this apporach would look like this:
https://github.com/boddob/linux/blob/c24cbf63a6998d00095c10122ce5e37b764c7db...
The main irritant with the '2 driver' approach is that we need to share the per-device driver data with them. For ADV7533, I've made the i2c driver allocate driver data (struct adv7511).
The dsi driver gets the driver data in the following way:
- The i2c driver sets the driver data as its client data using i2c_set_clientdata()
- Parse the i2c-control phandle to get the corresponding i2c client.
- Extract the adv7511 struct by getting i2c_get_clientdata()
This way of getting the same driver data is a bit strange, but it works. For this, we do need to ensure that the dsi driver defers as long as the i2c driver isn't probed.
I've now implemented both approaches for the driver. The first using a dummy dsi device, and this one using 2 drivers (with both being represented in DT). The advantage of the latter is that we don't need to create any dummy device stuff, the disadvantage is that DT is a bit uncommon.
Can we now come to a conclusion on what approach is better?
DSI by design is data bus which can be used additionally as a control bus, but in this particular case it is purely data bus. So of-graph bindings seem to be better choice. As already Lucas Stach said DT hierarchy should describe control buses and of-graph bindings should describe data bus. Argument that hw has two interfaces does not seem to be valid here - it has only one control interface. The other one is only for data, representing every data interface using DT hierarchy would lead to inflation of pseudo devices.
On the other side I do not see dummy device approach ideal solution, I guess lightweight framework providing DSI hosts detached from Linux device model could work better here. The only problem here is that it should coexist somehow with dsi bus used to control devices. Anyway implementing it shouldn't be hard, question is if it would be eventually accepted :) I guess we can live for now with dummy devs.
Summarizing I would prefer version with dummy devices, as it seems more compatible with DT design.
Thanks for the feedback. I'll spin a newer version of the dummy dsi dev patches after waiting for some more comments.
Let's wait for someone from the device tree maintainers to comment instead of going around in circles.
Thierry
On 9/15/2015 9:13 PM, Rob Herring wrote:
On 09/15/2015 05:32 AM, Archit Taneja wrote:
Hi Rob, Mark,
We've been trying to figure out the right way to represent a class of display encoder devices in DT.
I've been meaning to reply on this.
These devices have registers that are generally configured via i2c. Once the device is configured, it takes in video data from the mipi dsi bus.
Until now, all the devices we've supported devices that can be are configured by the dsi bus itself, and hence, we've been able to represent them in DT as children under the dsi host.
For the above class of devices (using both i2c and dsi), we aren't able to conclude upon what's the better approach among the two:
- Represent the device via 2 different nodes in DT. One would be
a child under an i2c adapter, the other a child of a dsi host. We would have two device drivers, one i2c client, and the other a mipi dsi device.
- Represent the device as an i2c client in DT. Provide an api
to create "dummy" dsi devices. The i2c client driver would use this api to register a dsi device, and link itself with the dsi host.
What do you think would be the way to go here? I guess you might have faced something similar in other subsystems.
The closest thing I can think of are WiFi/BT combo chips that use SDIO+UART. In that case, 2 nodes makes sense as these chips are essentially 2 independent functions in a single chip and both interfaces are control interfaces (as well as data). This case is a bit different with both interfaces being tied to the same function.
So in this case, I think option 2 is the right way for the reasons already outlined in this thread. I think there needs to be more consistency in how the of-graph connections are defined with the core doing more of the graph traversing. So having an i2c device plus of-graph seems more consistent with other non-DSI cases.
The main open issue seemed to be setting the VC. At least for the ADV7533, it can be whatever you want it to be. The host and device just need to agree. I see no need for that to be in DT at least in this case. But then I'm not sure what are typical constraints for VC assignment. I'd guess that constraints are on the device side and hosts can support whatever the device wants. If so, then it can purely be up to the driver to set.
2 DSI devices connected to the same host shouldn't have the same VC. When representing the DSI nodes via DT, we use the 'reg' property to assign the VC.
Although, in practice, we don't generally have multiple devices on the same bus. The trend is to have multiple DSI hosts on the platform to support more devices.
If we have checks that ensures the DT way and the new manual way of creation of DSI devices doesn't result in having conflicting VCs for devices, we should be okay.
Implementation-wise, I don't think that I'd call this a dummy device. There are multiple ways for devices to get created in the driver model. DT is just one way. You are just creating the device in a different way outside of DT which is fine.
Thanks for the feedback.
Archit
Hi Rob, Mark,
We've been trying to figure out the right way to represent a class of display encoder devices in DT.
These devices have registers that are generally configured via i2c. Once the device is configured, it takes in video data from the mipi dsi bus.
Until now, all the devices we've supported devices that can be are configured by the dsi bus itself, and hence, we've been able to represent them in DT as children under the dsi host.
For the above class of devices (using both i2c and dsi), we aren't able to conclude upon what's the better approach among the two:
1. Represent the device via 2 different nodes in DT. One would be a child under an i2c adapter, the other a child of a dsi host. We would have two device drivers, one i2c client, and the other a mipi dsi device.
2. Represent the device as an i2c client in DT. Provide an api to create "dummy" dsi devices. The i2c client driver would use this api to register a dsi device, and link itself with the dsi host.
What do you think would be the way to go here? I guess you might have faced something similar in other subsystems.
I've given a relatively brief description of the problem. There were some more nitty gritties discussed in this thread before.
Thierry, Andrzej, Lucas,
Please feel free to add your comments if I have missed out on something.
Thanks, Archit
On 09/10/2015 01:02 PM, Thierry Reding wrote:
On Thu, Sep 10, 2015 at 11:45:35AM +0530, Archit Taneja wrote:
On 09/08/2015 03:57 PM, Andrzej Hajda wrote:
On 09/07/2015 01:46 PM, Archit Taneja wrote:
Thierry,
On 08/21/2015 11:39 AM, Archit Taneja wrote:
On 08/20/2015 05:18 PM, Thierry Reding wrote:
On Thu, Aug 20, 2015 at 09:46:14AM +0530, Archit Taneja wrote: > Hi Thierry, Lucas, > > > On 08/19/2015 08:32 PM, Thierry Reding wrote: >> On Wed, Aug 19, 2015 at 04:52:24PM +0200, Lucas Stach wrote: >>> Am Mittwoch, den 19.08.2015, 16:34 +0200 schrieb Thierry Reding: >>>> On Wed, Aug 19, 2015 at 04:17:08PM +0200, Lucas Stach wrote: >>>>> Hi Thierry, Archit, >>>>> >>> [...] >>>>>> Perhaps a better way would be to invert this relationship. >>>>>> According to >>>>>> your proposal we'd have to have DT like this: >>>>>> >>>>>> i2c@... { >>>>>> ... >>>>>> >>>>>> dsi-device@... { >>>>>> ... >>>>>> dsi-bus = <&dsi>; >>>>>> ... >>>>>> }; >>>>>> >>>>>> ... >>>>>> }; >>>>>> >>>>>> dsi@... { >>>>>> ... >>>>>> }; >>>>>> >>>>>> Inversing the relationship would become something like this: >>>>>> >>>>>> i2c@... { >>>>>> ... >>>>>> }; >>>>>> >>>>>> dsi@... { >>>>>> ... >>>>>> >>>>>> peripheral@... { >>>>>> ... >>>>>> i2c-bus = <&i2c>; >>>>>> ... >>>>>> }; >>>>>> >>>>>> ... >>>>>> }; >>>>>> >>>>>> Both of those aren't fundamentally different, and they both have >>>>>> the >>>>>> disavantage of lacking ways to transport configuration data that >>>>>> the >>>>>> other bus needs to instantiate the dummy device (such as the reg >>>>>> property for example, denoting the I2C slave address or the DSI >>>>>> VC). >>>>>> >>>>>> So how about we create two devices in the device tree and fuse >>>>>> them at >>>>>> the driver level: >>>>>> >>>>>> i2c@... { >>>>>> ... >>>>>> >>>>>> i2cdsi: dsi-device@... { >>>>>> ... >>>>>> }; >>>>>> >>>>>> ... >>>>>> }; >>>>>> >>>>>> dsi@... { >>>>>> ... >>>>>> >>>>>> peripheral@... { >>>>>> ... >>>>>> control = <&i2cdsi>; >>>>>> ... >>>>>> }; >>>>>> >>>>>> ... >>>>>> }; >>>>>> >>>>>> This way we'll get both an I2C device and a DSI device that we >>>>>> can fully >>>>>> describe using the standard device tree bindings. At driver time >>>>>> we can >>>>>> get the I2C device from the phandle in the control property of >>>>>> the DSI >>>>>> device and use it to execute I2C transactions. >>>>>> >>>>> I don't really like to see that you are inventing yet-another-way to >>>>> handle devices connected to multiple buses. >>>>> >>>>> Devicetree is structured along the control buses, even if the >>>>> devices >>>>> are connected to multiple buses, in the DT they are always >>>>> children of >>>>> the bus that is used to control their registers from the CPUs >>>>> perspective. So a DSI encoder that is controlled through i2c is >>>>> clearly >>>>> a child of the i2c master controller and only of that one. >>>> >>>> I think that's a flawed interpretation of what's going on here. The >>>> device in fact has two interfaces: one is I2C, the other is DSI. >>>> In my >>>> opinion that's reason enough to represent it as two logical devices. >>>> >>> Does it really have 2 control interfaces that are used at the same >>> time? >>> Or is the DSI connection a passive data bus if the register control >>> happens through i2c? >> >> The interfaces may not be used at the same time, and the DSI interface >> may even be crippled, but the device is still addressable from the DSI >> host controller, if for nothing else than for routing the video stream. >> >>>>> If you need to model connections between devices that are not >>>>> reflected >>>>> through the control bus hierarchy you should really consider >>>>> using the >>>>> standardized of-graph bindings. >>>>> (Documentation/devicetree/bindings/graph.txt) >>>> >>>> The problem is that the original proposal would instantiate a dummy >>>> device, so it wouldn't be represented in DT at all. So unless you >>>> do add >>>> two logical devices to DT (one for each bus interface), you don't >>>> have >>>> anything to glue together with an OF graph. >>>> >>> I see that the having dummy device is the least desirable solution. >>> But >>> if there is only one control bus to the device I think it should be >>> one >>> device sitting beneath the control bus. >>> >>> You can then use of-graph to model the data path between the DSI >>> encoder >>> and device. >> >> But you will be needing a device below the DSI host controller to >> represent that endpoint of the connection. The DSI host controller >> itself is in no way connected to the I2C adapter. You would have to >> add some sort of quirk to the DSI controller binding to allow it to > > Thanks for the review. > > I implemented this to support ADV7533 DSI to HDMI encoder chip, which > has a DSI video bus and an i2c control bus. > > There weren't any quirks as such in the device tree when I tried to > implement this. The DT seems to manage fine without a node > corresponding to a mipi_dsi_device: > > i2c_adap@.. { > adv7533@.. { > > port { > adv_in: endpoint { > remote-endpoint = <&dsi_out>; > }; > }; > }; > }; > > dsi_host@.. { > ... > ... > > port { > dsi_out: endpoint { > remote-endpoint = <&adv_in>; > } > }; > }; > > It's the i2c driver's job to parse the graph and retrieve the > phandle to the dsi host. Using this, it can proceed with > registering itself to this host using the new dsi funcs. This > patch does the same for the adv7533 i2c driver: > > http://www.spinics.net/lists/dri-devel/msg86840.html > >> hook up with a control endpoint. And then you'll need more quirks >> to describe what kind of DSI device this is. > > Could you explain what you meant by this? I.e. describing the kind > of DSI device?
Describing the number of lanes, specifying the virtual channel, mode flags, etc. You could probably set the number of lanes and mode flags via the I2C driver, but especially the virtual channel cannot be set because it isn't known to the I2C DT branch of the device.
I agree with the VC part. It could be a DT entry within the i2c client node, but that does make it seem like a quirk. The 'reg' way under the DSI host is definitely better to populate the virtual channel.
> The dsi device created isn't really a dummy device as such. It's > dummy in the sense that there isn't a real dsi driver associated > with it. The dsi device is still used to attach to a mipi dsi host, > the way normal dsi devices do.
I understand, but I don't see why it has to be instantiated by the I2C driver, that's what I find backwards. There is already a standard way for instantiating DSI devices, why not use it?
I assumed we could either represent the device using an i2c driver, or dsi, but not both. Hence, I came up with this approach.
>> On the other hand if you properly instantiate the DSI device you can >> easily write a driver for it, and the driver will set up the correct >> properties as implied by the compatible string. Once you have that you >> can easily hook it up to the I2C control interface in whatever way you >> like, be that an OF graph or just a simple unidirectional link by >> phandle. >> > > With the fused approach you suggested, we would have 2 drivers: one i2c > and the other dsi. The i2c client driver would be more or less minimal, > preparing an i2c_client device for the dsi driver to use. Is my > understanding correct?
Correct. That's kind of similar to the way an HDMI encoder driver would use an I2C adapter to query EDID. The i2c_client device would be a means for the DSI driver to access the control interface.
Okay.
Although, I'm not sure about the HDMI encoder example. An HDMI encoder would read off edid directly from the adapter(with an address specified), it wouldn't need to create an i2c client device. Therefore, an HDMI encoder wouldn't need to have a separate node for i2c in DT.
> We can do without dummy dsi devices with this method. But, representing > a device with 2 DT nodes seems a bit off. We'd also need to compatible > strings for the same device, one for the i2c part, and the other for > the dsi part.
I agree that this somewhat stretches the capabilities of device tree. Another alternative I guess would be to not have a compatible string for the I2C device at all (that's technically not valid, I guess) because we really don't need an I2C driver for the device. What we really need is a DSI driver with a means to talk over some I2C bus with some other part of its device.
I think what the driver should 'really' be is a bit subjective, and can vary based on what the buses are used for in the device. For the Toshiba chip that Jani mentioned, it tends more towards a DSI driver. Whereas, for an ADV75xx chip, it's closer to an I2C driver since only I2C can be used to configure the chip registers.
Although, I agree with the point you made about the DSI bus here:
"and the DSI interface may even be crippled, but the device is still addressable from the DSI host controller, if for nothing else than for routing the video stream."
The fact that the data on the DSI bus contains routing information (i.e, virtual channel number) always gives it some 'control' aspect.
> From an adv75xx driver perspective, it should also support the ADV7511 > chip, which is a RGB/DPI to HDMI encoder. For adv7511, we don't need a > DSI DT node. It would be a bit inconsistent to have the bindings > require both DSI and I2C nodes for one chip, and only I2C node for the > other, with both chips being supported by the same driver.
Why would that be inconsistent? That sounds like the most accurate representation of the hardware to me.
Inconsistent wasn't the right term. I should have used 'uncommon' :) It's common for two chips of the same family to have a different set optional properties in DT, but it's not common for two chips of the same family to be represented by a different number of devices in DT.
I don't have an issue with the fused approach you suggested, as long as people are okay with the DT parts. Especially the part of needing 2 compatible strings in the DT.
I implemented the ADV7533 driver with the approach you suggested above (2 drivers for 2 different components of the chip). I posted it out just a while back (with you in loop).
The DT node with this apporach would look like this:
https://github.com/boddob/linux/blob/c24cbf63a6998d00095c10122ce5e37b764c7db...
The main irritant with the '2 driver' approach is that we need to share the per-device driver data with them. For ADV7533, I've made the i2c driver allocate driver data (struct adv7511).
The dsi driver gets the driver data in the following way:
- The i2c driver sets the driver data as its client data using i2c_set_clientdata()
- Parse the i2c-control phandle to get the corresponding i2c client.
- Extract the adv7511 struct by getting i2c_get_clientdata()
This way of getting the same driver data is a bit strange, but it works. For this, we do need to ensure that the dsi driver defers as long as the i2c driver isn't probed.
I've now implemented both approaches for the driver. The first using a dummy dsi device, and this one using 2 drivers (with both being represented in DT). The advantage of the latter is that we don't need to create any dummy device stuff, the disadvantage is that DT is a bit uncommon.
Can we now come to a conclusion on what approach is better?
DSI by design is data bus which can be used additionally as a control bus, but in this particular case it is purely data bus. So of-graph bindings seem to be better choice. As already Lucas Stach said DT hierarchy should describe control buses and of-graph bindings should describe data bus. Argument that hw has two interfaces does not seem to be valid here - it has only one control interface. The other one is only for data, representing every data interface using DT hierarchy would lead to inflation of pseudo devices.
On the other side I do not see dummy device approach ideal solution, I guess lightweight framework providing DSI hosts detached from Linux device model could work better here. The only problem here is that it should coexist somehow with dsi bus used to control devices. Anyway implementing it shouldn't be hard, question is if it would be eventually accepted :) I guess we can live for now with dummy devs.
Summarizing I would prefer version with dummy devices, as it seems more compatible with DT design.
Thanks for the feedback. I'll spin a newer version of the dummy dsi dev patches after waiting for some more comments.
Let's wait for someone from the device tree maintainers to comment instead of going around in circles.
Thierry
We are currently restricted when it comes to supporting DSI on devices that have a non-DSI control bus. For example, DSI encoder chips are available in the market that are configured via i2c. Configuring their registers via DSI bus is either optional or not available at all.
These devices still need to pass DSI parameters (data lanes, mode flags etc) to the DSI host they are connected to. We don't have a way to do that at the moment.
After some discussions on the previous RFC[1], we decided to support this by providing additional API in drm_mipi_dsi which lets us create new DSI devices without the need of them to have a DT node.
There are a couple of concerns I have about this patchset which I couldn't figure out a solution to (they are addressed in the individual patches too):
- Matching of non-DT devices: buses like i2c/spi populate id_table in their drivers to perform a match for the non-DT case. Is this something that we should do too?
- Race between host_unregister and device_unregister: The new API provides peripheral drivers to unregister the DSI devices they created by using mipi_dsi_device_unregister. If the dsi host unregisters first, the peripheral driver might have an unregistered device pointer without being aware of it.
Some comments on these would help.
[1]: https://lkml.org/lkml/2015/6/30/42
Archit Taneja (5): drm/dsi: Refactor device creation drm/dsi: Try to match non-DT dsi devices drm/dsi: Check for used channels drm/dsi: Add routine to unregister dsi device drm/dsi: Get DSI host by DT device node
drivers/gpu/drm/drm_mipi_dsi.c | 135 ++++++++++++++++++++++++++++++++--------- include/drm/drm_mipi_dsi.h | 27 +++++++++ 2 files changed, 132 insertions(+), 30 deletions(-)
Simplify the mipi dsi device creation process. device_initialize and device_add don't need to be called separately when creating mipi_dsi_device's. Use device_register instead to simplify things.
Create a helper function mipi_dsi_device_new which takes in struct mipi_dsi_device_info and mipi_dsi_host. It clubs the functions mipi_dsi_device_alloc and mipi_dsi_device_add into one.
mipi_dsi_device_info acts as a template to populate the dsi device information. This is populated by of_mipi_dsi_device_add and passed to mipi_dsi_device_new.
Later on, we'll provide mipi_dsi_device_new as a standalone way to create a dsi device not available via DT.
The new device creation process tries to closely follow what's been done in i2c_new_device in i2c-core.
Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 61 +++++++++++++++++------------------------- include/drm/drm_mipi_dsi.h | 15 +++++++++++ 2 files changed, 40 insertions(+), 36 deletions(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 2d5ca8ee..245ecfe 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -102,9 +102,18 @@ static const struct device_type mipi_dsi_device_type = { .release = mipi_dsi_dev_release, };
-static struct mipi_dsi_device *mipi_dsi_device_alloc(struct mipi_dsi_host *host) +struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, + struct mipi_dsi_device_info *info) { struct mipi_dsi_device *dsi; + struct device *dev = host->dev; + int r; + + if (info->reg > 3) { + dev_err(dev, "device node has invalid reg property: %u\n", + info->reg); + return ERR_PTR(-EINVAL); + }
dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); if (!dsi) @@ -114,26 +123,27 @@ static struct mipi_dsi_device *mipi_dsi_device_alloc(struct mipi_dsi_host *host) dsi->dev.bus = &mipi_dsi_bus_type; dsi->dev.parent = host->dev; dsi->dev.type = &mipi_dsi_device_type; + dsi->dev.of_node = info->node; + dsi->channel = info->reg;
- device_initialize(&dsi->dev); - - return dsi; -} - -static int mipi_dsi_device_add(struct mipi_dsi_device *dsi) -{ - struct mipi_dsi_host *host = dsi->host; + dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), info->reg);
- dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), dsi->channel); + r = device_register(&dsi->dev); + if (r) { + dev_err(dev, "failed to register device: %d\n", r); + kfree(dsi); + return ERR_PTR(r); + }
- return device_add(&dsi->dev); + return dsi; } +EXPORT_SYMBOL(mipi_dsi_device_new);
static struct mipi_dsi_device * of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) { - struct mipi_dsi_device *dsi; struct device *dev = host->dev; + struct mipi_dsi_device_info info = { }; int ret; u32 reg;
@@ -144,31 +154,10 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) return ERR_PTR(-EINVAL); }
- if (reg > 3) { - dev_err(dev, "device node %s has invalid reg property: %u\n", - node->full_name, reg); - return ERR_PTR(-EINVAL); - } - - dsi = mipi_dsi_device_alloc(host); - if (IS_ERR(dsi)) { - dev_err(dev, "failed to allocate DSI device %s: %ld\n", - node->full_name, PTR_ERR(dsi)); - return dsi; - } - - dsi->dev.of_node = of_node_get(node); - dsi->channel = reg; + info.reg = reg; + info.node = of_node_get(node);
- ret = mipi_dsi_device_add(dsi); - if (ret) { - dev_err(dev, "failed to add DSI device %s: %d\n", - node->full_name, ret); - kfree(dsi); - return ERR_PTR(ret); - } - - return dsi; + return mipi_dsi_device_new(host, &info); }
int mipi_dsi_host_register(struct mipi_dsi_host *host) diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index f1d8d0d..90f4f3c 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -140,6 +140,19 @@ enum mipi_dsi_pixel_format { };
/** + * struct mipi_dsi_device_info - template for creating a mipi_dsi_device + * @reg: DSI virtual channel assigned to peripheral + * @node: pointer to OF device node + * + * This is populated and passed to mipi_dsi_device_new to create a new + * DSI device + */ +struct mipi_dsi_device_info { + u32 reg; + struct device_node *node; +}; + +/** * struct mipi_dsi_device - DSI peripheral device * @host: DSI host for this peripheral * @dev: driver model device node for this peripheral @@ -174,6 +187,8 @@ ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload, ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params, size_t num_params, void *data, size_t size);
+struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, + struct mipi_dsi_device_info *info); /** * enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode * @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking
On 10/06/2015 11:24 AM, Archit Taneja wrote:
Simplify the mipi dsi device creation process. device_initialize and device_add don't need to be called separately when creating mipi_dsi_device's. Use device_register instead to simplify things.
Create a helper function mipi_dsi_device_new which takes in struct mipi_dsi_device_info and mipi_dsi_host. It clubs the functions mipi_dsi_device_alloc and mipi_dsi_device_add into one.
mipi_dsi_device_info acts as a template to populate the dsi device information. This is populated by of_mipi_dsi_device_add and passed to mipi_dsi_device_new.
Later on, we'll provide mipi_dsi_device_new as a standalone way to create a dsi device not available via DT.
The new device creation process tries to closely follow what's been done in i2c_new_device in i2c-core.
Signed-off-by: Archit Taneja architt@codeaurora.org
Reviewed-by: Andrzej Hajda a.hajda@samsung.com
Regards Andrzej
drivers/gpu/drm/drm_mipi_dsi.c | 61 +++++++++++++++++------------------------- include/drm/drm_mipi_dsi.h | 15 +++++++++++ 2 files changed, 40 insertions(+), 36 deletions(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 2d5ca8ee..245ecfe 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -102,9 +102,18 @@ static const struct device_type mipi_dsi_device_type = { .release = mipi_dsi_dev_release, };
-static struct mipi_dsi_device *mipi_dsi_device_alloc(struct mipi_dsi_host *host) +struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host,
struct mipi_dsi_device_info *info)
{ struct mipi_dsi_device *dsi;
- struct device *dev = host->dev;
- int r;
if (info->reg > 3) {
dev_err(dev, "device node has invalid reg property: %u\n",
info->reg);
return ERR_PTR(-EINVAL);
}
dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); if (!dsi)
@@ -114,26 +123,27 @@ static struct mipi_dsi_device *mipi_dsi_device_alloc(struct mipi_dsi_host *host) dsi->dev.bus = &mipi_dsi_bus_type; dsi->dev.parent = host->dev; dsi->dev.type = &mipi_dsi_device_type;
- dsi->dev.of_node = info->node;
- dsi->channel = info->reg;
- device_initialize(&dsi->dev);
- return dsi;
-}
-static int mipi_dsi_device_add(struct mipi_dsi_device *dsi) -{
- struct mipi_dsi_host *host = dsi->host;
- dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), info->reg);
- dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), dsi->channel);
- r = device_register(&dsi->dev);
- if (r) {
dev_err(dev, "failed to register device: %d\n", r);
kfree(dsi);
return ERR_PTR(r);
- }
- return device_add(&dsi->dev);
- return dsi;
} +EXPORT_SYMBOL(mipi_dsi_device_new);
static struct mipi_dsi_device * of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) {
- struct mipi_dsi_device *dsi; struct device *dev = host->dev;
- struct mipi_dsi_device_info info = { }; int ret; u32 reg;
@@ -144,31 +154,10 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) return ERR_PTR(-EINVAL); }
- if (reg > 3) {
dev_err(dev, "device node %s has invalid reg property: %u\n",
node->full_name, reg);
return ERR_PTR(-EINVAL);
- }
- dsi = mipi_dsi_device_alloc(host);
- if (IS_ERR(dsi)) {
dev_err(dev, "failed to allocate DSI device %s: %ld\n",
node->full_name, PTR_ERR(dsi));
return dsi;
- }
- dsi->dev.of_node = of_node_get(node);
- dsi->channel = reg;
- info.reg = reg;
- info.node = of_node_get(node);
- ret = mipi_dsi_device_add(dsi);
- if (ret) {
dev_err(dev, "failed to add DSI device %s: %d\n",
node->full_name, ret);
kfree(dsi);
return ERR_PTR(ret);
- }
- return dsi;
- return mipi_dsi_device_new(host, &info);
}
int mipi_dsi_host_register(struct mipi_dsi_host *host) diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index f1d8d0d..90f4f3c 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -140,6 +140,19 @@ enum mipi_dsi_pixel_format { };
/**
- struct mipi_dsi_device_info - template for creating a mipi_dsi_device
- @reg: DSI virtual channel assigned to peripheral
- @node: pointer to OF device node
- This is populated and passed to mipi_dsi_device_new to create a new
- DSI device
- */
+struct mipi_dsi_device_info {
- u32 reg;
- struct device_node *node;
+};
+/**
- struct mipi_dsi_device - DSI peripheral device
- @host: DSI host for this peripheral
- @dev: driver model device node for this peripheral
@@ -174,6 +187,8 @@ ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload, ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params, size_t num_params, void *data, size_t size);
+struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host,
struct mipi_dsi_device_info *info);
/**
- enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode
- @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking
Add a device name field in mipi_dsi_device. This name is different from the actual dev name (which is of the format "hostname.reg"). When the device is created via DT, this name is set to the modalias string. In the non-DT case, the driver creating the DSI device provides the name by populating a filed in mipi_dsi_device_info.
Matching for DT case would be as it was before. For the non-DT case, we compare the device and driver names. Matching by comparing driver and device names isn't the best thing to do. I'd appreciate some suggestions here.
Other buses (like i2c/spi) perform a non-DT match by comparing the device name and entries in the driver's id_table. The id_table structs for different buses are defined in "include/linux/mod_devicetable.h", I didn't want to touch that for now.
Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 29 ++++++++++++++++++++++++++++- include/drm/drm_mipi_dsi.h | 8 ++++++++ 2 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 245ecfe..46ee515 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -45,9 +45,30 @@ * subset of the MIPI DCS command set. */
+static const struct device_type mipi_dsi_device_type; + static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv) { - return of_driver_match_device(dev, drv); + struct mipi_dsi_device *dsi; + + if (dev->type == &mipi_dsi_device_type) + dsi = to_mipi_dsi_device(dev); + else + return 0; + + /* Attempt OF style match */ + if (of_driver_match_device(dev, drv)) + return 1; + + /* + * Try to compare dsi device and driver names. If this matching approach + * isn't strong, we'd probably want the dsi drivers to populate the + * id_table field and use that instead + */ + if (!strcmp(dsi->name, drv->name)) + return 1; + + return 0; }
static const struct dev_pm_ops mipi_dsi_device_pm_ops = { @@ -125,6 +146,7 @@ struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, dsi->dev.type = &mipi_dsi_device_type; dsi->dev.of_node = info->node; dsi->channel = info->reg; + strlcpy(dsi->name, info->name, sizeof(dsi->name));
dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), info->reg);
@@ -147,6 +169,11 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) int ret; u32 reg;
+ if (of_modalias_node(node, info.name, sizeof(info.name)) < 0) { + dev_err(dev, "modalias failure on %s\n", node->full_name); + return ERR_PTR(-EINVAL); + } + ret = of_property_read_u32(node, "reg", ®); if (ret) { dev_err(dev, "device node %s has no valid reg property: %d\n", diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 90f4f3c..93dec7b 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -139,8 +139,11 @@ enum mipi_dsi_pixel_format { MIPI_DSI_FMT_RGB565, };
+#define DSI_DEV_NAME_SIZE 20 + /** * struct mipi_dsi_device_info - template for creating a mipi_dsi_device + * @name: name of the dsi peripheral * @reg: DSI virtual channel assigned to peripheral * @node: pointer to OF device node * @@ -148,14 +151,17 @@ enum mipi_dsi_pixel_format { * DSI device */ struct mipi_dsi_device_info { + char name[DSI_DEV_NAME_SIZE]; u32 reg; struct device_node *node; };
+ /** * struct mipi_dsi_device - DSI peripheral device * @host: DSI host for this peripheral * @dev: driver model device node for this peripheral + * @name: name of the dsi peripheral * @channel: virtual channel assigned to the peripheral * @format: pixel format for video mode * @lanes: number of active data lanes @@ -165,6 +171,8 @@ struct mipi_dsi_device { struct mipi_dsi_host *host; struct device dev;
+ char name[DSI_DEV_NAME_SIZE]; + unsigned int channel; unsigned int lanes; enum mipi_dsi_pixel_format format;
On 10/06/2015 11:24 AM, Archit Taneja wrote:
Add a device name field in mipi_dsi_device. This name is different from the actual dev name (which is of the format "hostname.reg"). When the device is created via DT, this name is set to the modalias string. In the non-DT case, the driver creating the DSI device provides the name by populating a filed in mipi_dsi_device_info.
Matching for DT case would be as it was before. For the non-DT case, we compare the device and driver names. Matching by comparing driver and device names isn't the best thing to do. I'd appreciate some suggestions here.
Other buses (like i2c/spi) perform a non-DT match by comparing the device name and entries in the driver's id_table. The id_table structs for different buses are defined in "include/linux/mod_devicetable.h", I didn't want to touch that for now.
Signed-off-by: Archit Taneja architt@codeaurora.org
Beside small comments below.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com
drivers/gpu/drm/drm_mipi_dsi.c | 29 ++++++++++++++++++++++++++++- include/drm/drm_mipi_dsi.h | 8 ++++++++ 2 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 245ecfe..46ee515 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -45,9 +45,30 @@
- subset of the MIPI DCS command set.
*/
+static const struct device_type mipi_dsi_device_type;
static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv) {
- return of_driver_match_device(dev, drv);
- struct mipi_dsi_device *dsi;
- if (dev->type == &mipi_dsi_device_type)
dsi = to_mipi_dsi_device(dev);
- else
return 0;
- /* Attempt OF style match */
- if (of_driver_match_device(dev, drv))
return 1;
- /*
* Try to compare dsi device and driver names. If this matching approach
* isn't strong, we'd probably want the dsi drivers to populate the
* id_table field and use that instead
*/
- if (!strcmp(dsi->name, drv->name))
return 1;
- return 0;
}
static const struct dev_pm_ops mipi_dsi_device_pm_ops = { @@ -125,6 +146,7 @@ struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, dsi->dev.type = &mipi_dsi_device_type; dsi->dev.of_node = info->node; dsi->channel = info->reg;
strlcpy(dsi->name, info->name, sizeof(dsi->name));
dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), info->reg);
@@ -147,6 +169,11 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) int ret; u32 reg;
- if (of_modalias_node(node, info.name, sizeof(info.name)) < 0) {
dev_err(dev, "modalias failure on %s\n", node->full_name);
return ERR_PTR(-EINVAL);
- }
- ret = of_property_read_u32(node, "reg", ®); if (ret) { dev_err(dev, "device node %s has no valid reg property: %d\n",
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 90f4f3c..93dec7b 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -139,8 +139,11 @@ enum mipi_dsi_pixel_format { MIPI_DSI_FMT_RGB565, };
+#define DSI_DEV_NAME_SIZE 20
/**
- struct mipi_dsi_device_info - template for creating a mipi_dsi_device
- @name: name of the dsi peripheral
- @reg: DSI virtual channel assigned to peripheral
- @node: pointer to OF device node
@@ -148,14 +151,17 @@ enum mipi_dsi_pixel_format {
- DSI device
*/ struct mipi_dsi_device_info {
- char name[DSI_DEV_NAME_SIZE];
I wonder if it shouldn't be called type as in case of i2c, but no strong feelings.
u32 reg; struct device_node *node; };
Empty line.
/**
- struct mipi_dsi_device - DSI peripheral device
- @host: DSI host for this peripheral
- @dev: driver model device node for this peripheral
- @name: name of the dsi peripheral
- @channel: virtual channel assigned to the peripheral
- @format: pixel format for video mode
- @lanes: number of active data lanes
@@ -165,6 +171,8 @@ struct mipi_dsi_device { struct mipi_dsi_host *host; struct device dev;
- char name[DSI_DEV_NAME_SIZE];
This empty line can be also removed.
Regards Andrzej
unsigned int channel; unsigned int lanes; enum mipi_dsi_pixel_format format;
On 10/30/2015 06:12 PM, Andrzej Hajda wrote:
On 10/06/2015 11:24 AM, Archit Taneja wrote:
Add a device name field in mipi_dsi_device. This name is different from the actual dev name (which is of the format "hostname.reg"). When the device is created via DT, this name is set to the modalias string. In the non-DT case, the driver creating the DSI device provides the name by populating a filed in mipi_dsi_device_info.
Matching for DT case would be as it was before. For the non-DT case, we compare the device and driver names. Matching by comparing driver and device names isn't the best thing to do. I'd appreciate some suggestions here.
Other buses (like i2c/spi) perform a non-DT match by comparing the device name and entries in the driver's id_table. The id_table structs for different buses are defined in "include/linux/mod_devicetable.h", I didn't want to touch that for now.
Signed-off-by: Archit Taneja architt@codeaurora.org
Beside small comments below.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com
drivers/gpu/drm/drm_mipi_dsi.c | 29 ++++++++++++++++++++++++++++- include/drm/drm_mipi_dsi.h | 8 ++++++++ 2 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 245ecfe..46ee515 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -45,9 +45,30 @@
- subset of the MIPI DCS command set.
*/
+static const struct device_type mipi_dsi_device_type;
- static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv) {
- return of_driver_match_device(dev, drv);
struct mipi_dsi_device *dsi;
if (dev->type == &mipi_dsi_device_type)
dsi = to_mipi_dsi_device(dev);
else
return 0;
/* Attempt OF style match */
if (of_driver_match_device(dev, drv))
return 1;
/*
* Try to compare dsi device and driver names. If this matching approach
* isn't strong, we'd probably want the dsi drivers to populate the
* id_table field and use that instead
*/
if (!strcmp(dsi->name, drv->name))
return 1;
return 0; }
static const struct dev_pm_ops mipi_dsi_device_pm_ops = {
@@ -125,6 +146,7 @@ struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, dsi->dev.type = &mipi_dsi_device_type; dsi->dev.of_node = info->node; dsi->channel = info->reg;
strlcpy(dsi->name, info->name, sizeof(dsi->name));
dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), info->reg);
@@ -147,6 +169,11 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) int ret; u32 reg;
- if (of_modalias_node(node, info.name, sizeof(info.name)) < 0) {
dev_err(dev, "modalias failure on %s\n", node->full_name);
return ERR_PTR(-EINVAL);
- }
- ret = of_property_read_u32(node, "reg", ®); if (ret) { dev_err(dev, "device node %s has no valid reg property: %d\n",
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 90f4f3c..93dec7b 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -139,8 +139,11 @@ enum mipi_dsi_pixel_format { MIPI_DSI_FMT_RGB565, };
+#define DSI_DEV_NAME_SIZE 20
- /**
- struct mipi_dsi_device_info - template for creating a mipi_dsi_device
- @name: name of the dsi peripheral
- @reg: DSI virtual channel assigned to peripheral
- @node: pointer to OF device node
@@ -148,14 +151,17 @@ enum mipi_dsi_pixel_format {
- DSI device
*/ struct mipi_dsi_device_info {
- char name[DSI_DEV_NAME_SIZE];
I wonder if it shouldn't be called type as in case of i2c, but no strong feelings.
We could change it to 'type'. It'll be easier for someone to understand what the dsi core is doing by keeping the same nomenclature as in i2c-core.
u32 reg; struct device_node *node; };
Empty line.
/**
- struct mipi_dsi_device - DSI peripheral device
- @host: DSI host for this peripheral
- @dev: driver model device node for this peripheral
- @name: name of the dsi peripheral
- @channel: virtual channel assigned to the peripheral
- @format: pixel format for video mode
- @lanes: number of active data lanes
@@ -165,6 +171,8 @@ struct mipi_dsi_device { struct mipi_dsi_host *host; struct device dev;
- char name[DSI_DEV_NAME_SIZE];
This empty line can be also removed.
Will remove these.
Thanks, Archit
Regards Andrzej
unsigned int channel; unsigned int lanes; enum mipi_dsi_pixel_format format;
-- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
We don't check whether a previously registered mipi_dsi_device under the same host shares the same virtual channel.
Before registering, check if any of the registered devices doesn't already have the same virtual channel.
This wasn't crucial when all the devices under a host were populated via DT. Now that we also support creating devices manually, we could end up in a situation where a driver tries to create a device with a virtual channel already taken by a device populated in DT.
Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 46ee515..db6130a 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -123,6 +123,22 @@ static const struct device_type mipi_dsi_device_type = { .release = mipi_dsi_dev_release, };
+static int __dsi_check_chan_busy(struct device *dev, void *data) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); + u32 reg = *(u32 *) data; + + if (dsi && dsi->channel == reg) + return -EBUSY; + + return 0; +} + +static int mipi_dsi_check_chan_busy(struct mipi_dsi_host *host, u32 reg) +{ + return device_for_each_child(host->dev, ®, __dsi_check_chan_busy); +} + struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, struct mipi_dsi_device_info *info) { @@ -150,14 +166,20 @@ struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host,
dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), info->reg);
+ r = mipi_dsi_check_chan_busy(host, info->reg); + if (r) + goto err; + r = device_register(&dsi->dev); if (r) { dev_err(dev, "failed to register device: %d\n", r); - kfree(dsi); - return ERR_PTR(r); + goto err; }
return dsi; +err: + kfree(dsi); + return ERR_PTR(r); } EXPORT_SYMBOL(mipi_dsi_device_new);
On 10/06/2015 11:24 AM, Archit Taneja wrote:
We don't check whether a previously registered mipi_dsi_device under the same host shares the same virtual channel.
Before registering, check if any of the registered devices doesn't already have the same virtual channel.
This wasn't crucial when all the devices under a host were populated via DT. Now that we also support creating devices manually, we could end up in a situation where a driver tries to create a device with a virtual channel already taken by a device populated in DT.
Signed-off-by: Archit Taneja architt@codeaurora.org
Beside few non-blcking nitpicks.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com
drivers/gpu/drm/drm_mipi_dsi.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 46ee515..db6130a 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -123,6 +123,22 @@ static const struct device_type mipi_dsi_device_type = { .release = mipi_dsi_dev_release, };
+static int __dsi_check_chan_busy(struct device *dev, void *data) +{
- struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
- u32 reg = *(u32 *) data;
- if (dsi && dsi->channel == reg)
Maybe simpler would be:
u32 *reg = data;
if (dsi && dsi->channel == *reg)
return -EBUSY;
- return 0;
+}
+static int mipi_dsi_check_chan_busy(struct mipi_dsi_host *host, u32 reg) +{
- return device_for_each_child(host->dev, ®, __dsi_check_chan_busy);
+}
struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, struct mipi_dsi_device_info *info) { @@ -150,14 +166,20 @@ struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host,
dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), info->reg);
- r = mipi_dsi_check_chan_busy(host, info->reg);
I know this r variable was introduced in the 1st patch, but if you will send next iteration consider replacing it with ret, looks more readable and follows file convention :)
Regards Andrzej
- if (r)
goto err;
- r = device_register(&dsi->dev); if (r) { dev_err(dev, "failed to register device: %d\n", r);
kfree(dsi);
return ERR_PTR(r);
goto err;
}
return dsi;
+err:
- kfree(dsi);
- return ERR_PTR(r);
} EXPORT_SYMBOL(mipi_dsi_device_new);
On 10/30/2015 06:22 PM, Andrzej Hajda wrote:
On 10/06/2015 11:24 AM, Archit Taneja wrote:
We don't check whether a previously registered mipi_dsi_device under the same host shares the same virtual channel.
Before registering, check if any of the registered devices doesn't already have the same virtual channel.
This wasn't crucial when all the devices under a host were populated via DT. Now that we also support creating devices manually, we could end up in a situation where a driver tries to create a device with a virtual channel already taken by a device populated in DT.
Signed-off-by: Archit Taneja architt@codeaurora.org
Beside few non-blcking nitpicks.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com
drivers/gpu/drm/drm_mipi_dsi.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 46ee515..db6130a 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -123,6 +123,22 @@ static const struct device_type mipi_dsi_device_type = { .release = mipi_dsi_dev_release, };
+static int __dsi_check_chan_busy(struct device *dev, void *data) +{
- struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
- u32 reg = *(u32 *) data;
- if (dsi && dsi->channel == reg)
Maybe simpler would be:
u32 *reg = data; if (dsi && dsi->channel == *reg)
This is better. I'll change it to this.
return -EBUSY;
- return 0;
+}
+static int mipi_dsi_check_chan_busy(struct mipi_dsi_host *host, u32 reg) +{
- return device_for_each_child(host->dev, ®, __dsi_check_chan_busy);
+}
- struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, struct mipi_dsi_device_info *info) {
@@ -150,14 +166,20 @@ struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host,
dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), info->reg);
- r = mipi_dsi_check_chan_busy(host, info->reg);
I know this r variable was introduced in the 1st patch, but if you will send next iteration consider replacing it with ret, looks more readable and follows file convention :)
I'll probably end up sending another iteration (or more). I'll change the name.
Thanks, Archit
Regards Andrzej
- if (r)
goto err;
- r = device_register(&dsi->dev); if (r) { dev_err(dev, "failed to register device: %d\n", r);
kfree(dsi);
return ERR_PTR(r);
goto err;
}
return dsi;
+err:
- kfree(dsi);
- return ERR_PTR(r); } EXPORT_SYMBOL(mipi_dsi_device_new);
-- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
A driver calling mipi_dsi_device_new might want to unregister the device once it's done. It might also require it in an error handling path in case something didn't go right.
When the dsi host driver calls mipi_dsi_host_unregister, the devices created by both DT and and without DT will be removed. This does leave the possibility of the host removing the dsi device without the peripheral driver being aware of it. I don't know a good way to solve this. Some suggestions here would be of help too.
Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 7 +++++++ include/drm/drm_mipi_dsi.h | 2 ++ 2 files changed, 9 insertions(+)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index db6130a..cbb7373 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -183,6 +183,13 @@ err: } EXPORT_SYMBOL(mipi_dsi_device_new);
+void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi) +{ + if (dsi) + device_unregister(&dsi->dev); +} +EXPORT_SYMBOL(mipi_dsi_device_unregister); + static struct mipi_dsi_device * of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) { diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 93dec7b..68f49f4 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -197,6 +197,8 @@ ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,
struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, struct mipi_dsi_device_info *info); +void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi); + /** * enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode * @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking
On 10/06/2015 11:24 AM, Archit Taneja wrote:
A driver calling mipi_dsi_device_new might want to unregister the device once it's done. It might also require it in an error handling path in case something didn't go right.
When the dsi host driver calls mipi_dsi_host_unregister, the devices created by both DT and and without DT will be removed. This does leave the possibility of the host removing the dsi device without the peripheral driver being aware of it. I don't know a good way to solve this. Some suggestions here would be of help too.
The 2nd paragraph is not relevant here. It is another issue. Some comments about it: I am not sure, but I guess device should not be removed if it is refcounted properly, it will be just detached from the driver, bus and system (whatever it means:) ). It does not mean it will be usable and probably some races can occur anyway. I guess i2c and other buses have the same problem, am I right?
Signed-off-by: Archit Taneja architt@codeaurora.org
drivers/gpu/drm/drm_mipi_dsi.c | 7 +++++++ include/drm/drm_mipi_dsi.h | 2 ++ 2 files changed, 9 insertions(+)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index db6130a..cbb7373 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -183,6 +183,13 @@ err: } EXPORT_SYMBOL(mipi_dsi_device_new);
+void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi) +{
- if (dsi)
device_unregister(&dsi->dev);
+} +EXPORT_SYMBOL(mipi_dsi_device_unregister);
I guess NULL check can be removed and the whole function can be inlined.
Regards Andrzej
static struct mipi_dsi_device * of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) { diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 93dec7b..68f49f4 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -197,6 +197,8 @@ ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,
struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, struct mipi_dsi_device_info *info); +void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi);
/**
- enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode
- @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking
On 10/30/2015 07:51 PM, Andrzej Hajda wrote:
On 10/06/2015 11:24 AM, Archit Taneja wrote:
A driver calling mipi_dsi_device_new might want to unregister the device once it's done. It might also require it in an error handling path in case something didn't go right.
When the dsi host driver calls mipi_dsi_host_unregister, the devices created by both DT and and without DT will be removed. This does leave the possibility of the host removing the dsi device without the peripheral driver being aware of it. I don't know a good way to solve this. Some suggestions here would be of help too.
The 2nd paragraph is not relevant here. It is another issue. Some comments about it:
Yes, it's probably not the best to put it in the commit message of this patch.
I am not sure, but I guess device should not be removed if it is refcounted properly, it will be just detached from the driver, bus and system (whatever it means:) ). It does not mean it will be usable and probably some races can occur anyway. I guess i2c and other buses have the same problem, am I right?
I was concerned about one particular sequence:
1) DSI host driver calls mipi_dsi_host_unregister: All dsi devices would be unregistered.
2) dsi device driver calls mipi_dsi_device_unregister: This will try to unregister our dsi device
The problem here is that the device will cease to exist after step (1) itself, because the refcount of our device will never be 2.
mipi_dsi_host_register() will only register devices represented in DT, not the one the drivers register manually.
In other words, the dsi pointer in our driver will point to nothing valid after mipi_dsi_host_unregister is called.
As you said, I guess this exists in other buses too, and it's the drivers job to not use them.
Signed-off-by: Archit Taneja architt@codeaurora.org
drivers/gpu/drm/drm_mipi_dsi.c | 7 +++++++ include/drm/drm_mipi_dsi.h | 2 ++ 2 files changed, 9 insertions(+)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index db6130a..cbb7373 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -183,6 +183,13 @@ err: } EXPORT_SYMBOL(mipi_dsi_device_new);
+void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi) +{
- if (dsi)
device_unregister(&dsi->dev);
+} +EXPORT_SYMBOL(mipi_dsi_device_unregister);
I guess NULL check can be removed and the whole function can be inlined.
Yeah, this check won't help anyway.
I think I'll mention that drivers should use this only in error handling paths, and not in the driver's remove() op.
I'll also change this to inlined.
Archit
Regards Andrzej
static struct mipi_dsi_device * of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) { diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 93dec7b..68f49f4 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -197,6 +197,8 @@ ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,
struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, struct mipi_dsi_device_info *info); +void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi);
- /**
- enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode
- @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking
-- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 11/02/2015 07:28 AM, Archit Taneja wrote:
On 10/30/2015 07:51 PM, Andrzej Hajda wrote:
On 10/06/2015 11:24 AM, Archit Taneja wrote:
A driver calling mipi_dsi_device_new might want to unregister the device once it's done. It might also require it in an error handling path in case something didn't go right.
When the dsi host driver calls mipi_dsi_host_unregister, the devices created by both DT and and without DT will be removed. This does leave the possibility of the host removing the dsi device without the peripheral driver being aware of it. I don't know a good way to solve this. Some suggestions here would be of help too.
The 2nd paragraph is not relevant here. It is another issue. Some comments about it:
Yes, it's probably not the best to put it in the commit message of this patch.
I am not sure, but I guess device should not be removed if it is refcounted properly, it will be just detached from the driver, bus and system (whatever it means:) ). It does not mean it will be usable and probably some races can occur anyway. I guess i2c and other buses have the same problem, am I right?
I was concerned about one particular sequence:
- DSI host driver calls mipi_dsi_host_unregister: All dsi devices would
be unregistered.
- dsi device driver calls mipi_dsi_device_unregister: This will try to
unregister our dsi device
The problem here is that the device will cease to exist after step (1) itself, because the refcount of our device will never be 2.
mipi_dsi_host_register() will only register devices represented in DT, not the one the drivers register manually.
In other words, the dsi pointer in our driver will point to nothing valid after mipi_dsi_host_unregister is called.
As you said, I guess this exists in other buses too, and it's the drivers job to not use them.
I think the whole problem is due to fact we try to use devices as interfaces to some bus hosts (DSI in our case), these devices are owned by bus host and we cannot control their lifetime from other code. The best solution IMO would be to create separate lightweight framework as I suggested in previous discussion[1]. It should be cleaner solution without any 'dummy' proxy devices. But even in this case we would need some callbacks to notify that the provider is about to be removed.
2nd 'solution' is to leave it as is and pretend everything is OK, as in case of other frameworks :)
Maybe it would be possible 3rd solution - we could use probe and remove callbacks from dsi driver to notify clients about adding/removal of dsi device to/from bus. So during dummy dsi dev creation we would provide some callbacks which would be called by dummy dsi driver probe/remove to notifiy client it can start/stop using dsi device. This crazy construction probably can work but looks insane :)
[1]: http://www.spinics.net/lists/linux-arm-msm/msg16945.html
Regards Andrzej
Signed-off-by: Archit Taneja architt@codeaurora.org
drivers/gpu/drm/drm_mipi_dsi.c | 7 +++++++ include/drm/drm_mipi_dsi.h | 2 ++ 2 files changed, 9 insertions(+)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index db6130a..cbb7373 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -183,6 +183,13 @@ err: } EXPORT_SYMBOL(mipi_dsi_device_new);
+void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi) +{
- if (dsi)
device_unregister(&dsi->dev);
+} +EXPORT_SYMBOL(mipi_dsi_device_unregister);
I guess NULL check can be removed and the whole function can be inlined.
Yeah, this check won't help anyway.
I think I'll mention that drivers should use this only in error handling paths, and not in the driver's remove() op.
I'll also change this to inlined.
Archit
Regards Andrzej
static struct mipi_dsi_device * of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) { diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 93dec7b..68f49f4 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -197,6 +197,8 @@ ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,
struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, struct mipi_dsi_device_info *info); +void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi);
- /**
- enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode
- @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking
-- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 11/02/2015 04:12 PM, Andrzej Hajda wrote:
On 11/02/2015 07:28 AM, Archit Taneja wrote:
On 10/30/2015 07:51 PM, Andrzej Hajda wrote:
On 10/06/2015 11:24 AM, Archit Taneja wrote:
A driver calling mipi_dsi_device_new might want to unregister the device once it's done. It might also require it in an error handling path in case something didn't go right.
When the dsi host driver calls mipi_dsi_host_unregister, the devices created by both DT and and without DT will be removed. This does leave the possibility of the host removing the dsi device without the peripheral driver being aware of it. I don't know a good way to solve this. Some suggestions here would be of help too.
The 2nd paragraph is not relevant here. It is another issue. Some comments about it:
Yes, it's probably not the best to put it in the commit message of this patch.
I am not sure, but I guess device should not be removed if it is refcounted properly, it will be just detached from the driver, bus and system (whatever it means:) ). It does not mean it will be usable and probably some races can occur anyway. I guess i2c and other buses have the same problem, am I right?
I was concerned about one particular sequence:
- DSI host driver calls mipi_dsi_host_unregister: All dsi devices would
be unregistered.
- dsi device driver calls mipi_dsi_device_unregister: This will try to
unregister our dsi device
The problem here is that the device will cease to exist after step (1) itself, because the refcount of our device will never be 2.
mipi_dsi_host_register() will only register devices represented in DT, not the one the drivers register manually.
In other words, the dsi pointer in our driver will point to nothing valid after mipi_dsi_host_unregister is called.
As you said, I guess this exists in other buses too, and it's the drivers job to not use them.
I think the whole problem is due to fact we try to use devices as interfaces to some bus hosts (DSI in our case), these devices are owned by bus host and we cannot control their lifetime from other code. The best solution IMO would be to create separate lightweight framework as I suggested in previous discussion[1]. It should be cleaner solution without any 'dummy' proxy devices. But even in this case we would need some callbacks to notify that the provider is about to be removed.
2nd 'solution' is to leave it as is and pretend everything is OK, as in case of other frameworks :)
Maybe it would be possible 3rd solution - we could use probe and remove callbacks from dsi driver to notify clients about adding/removal of dsi device to/from bus. So during dummy dsi dev creation we would provide some callbacks which would be called by dummy dsi driver probe/remove to notifiy client it can start/stop using dsi device. This crazy construction probably can work but looks insane :)
I'm okay with the 2nd solution :). We can add callbacks or a notification mechanism if anyone needs it in the future.
Thanks, Archit
Regards Andrzej
Signed-off-by: Archit Taneja architt@codeaurora.org
drivers/gpu/drm/drm_mipi_dsi.c | 7 +++++++ include/drm/drm_mipi_dsi.h | 2 ++ 2 files changed, 9 insertions(+)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index db6130a..cbb7373 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -183,6 +183,13 @@ err: } EXPORT_SYMBOL(mipi_dsi_device_new);
+void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi) +{
- if (dsi)
device_unregister(&dsi->dev);
+} +EXPORT_SYMBOL(mipi_dsi_device_unregister);
I guess NULL check can be removed and the whole function can be inlined.
Yeah, this check won't help anyway.
I think I'll mention that drivers should use this only in error handling paths, and not in the driver's remove() op.
I'll also change this to inlined.
Archit
Regards Andrzej
static struct mipi_dsi_device * of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) { diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 93dec7b..68f49f4 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -197,6 +197,8 @@ ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,
struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, struct mipi_dsi_device_info *info); +void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi);
- /**
- enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode
- @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking
-- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
-- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
mipi_dsi_devices are inherently aware of their host because they share a parent-child hierarchy in the device tree.
Non-dsi drivers that create a dummy dsi device don't have this data. In order to get this information, they require to a phandle to the dsi host in the device tree.
Maintain a list of all the hosts DSI that are currently registered.
This list will be used to find the mipi_dsi_host corresponding to the device_node passed in of_find_mipi_dsi_host_by_node.
Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 30 ++++++++++++++++++++++++++++++ include/drm/drm_mipi_dsi.h | 2 ++ 2 files changed, 32 insertions(+)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index cbb7373..c51d73e 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -216,6 +216,28 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) return mipi_dsi_device_new(host, &info); }
+static DEFINE_MUTEX(host_lock); +static LIST_HEAD(host_list); + +struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node) +{ + struct mipi_dsi_host *host; + + mutex_lock(&host_lock); + + list_for_each_entry(host, &host_list, list) { + if (host->dev->of_node == node) { + mutex_unlock(&host_lock); + return host; + } + } + + mutex_unlock(&host_lock); + + return NULL; +} +EXPORT_SYMBOL(of_find_mipi_dsi_host_by_node); + int mipi_dsi_host_register(struct mipi_dsi_host *host) { struct device_node *node; @@ -227,6 +249,10 @@ int mipi_dsi_host_register(struct mipi_dsi_host *host) of_mipi_dsi_device_add(host, node); }
+ mutex_lock(&host_lock); + list_add_tail(&host->list, &host_list); + mutex_unlock(&host_lock); + return 0; } EXPORT_SYMBOL(mipi_dsi_host_register); @@ -243,6 +269,10 @@ static int mipi_dsi_remove_device_fn(struct device *dev, void *priv) void mipi_dsi_host_unregister(struct mipi_dsi_host *host) { device_for_each_child(host->dev, NULL, mipi_dsi_remove_device_fn); + + mutex_lock(&host_lock); + list_del_init(&host->list); + mutex_unlock(&host_lock); } EXPORT_SYMBOL(mipi_dsi_host_unregister);
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 68f49f4..15d3068 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -100,10 +100,12 @@ struct mipi_dsi_host_ops { struct mipi_dsi_host { struct device *dev; const struct mipi_dsi_host_ops *ops; + struct list_head list; };
int mipi_dsi_host_register(struct mipi_dsi_host *host); void mipi_dsi_host_unregister(struct mipi_dsi_host *host); +struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node);
/* DSI mode flags */
Hi Archit,
[auto build test WARNING on v4.3-rc4 -- if it's inappropriate base, please ignore]
reproduce: make htmldocs
All warnings (new ones prefixed by >>):
drivers/gpu/drm/i915/i915_irq.c:491: warning: No description found for parameter 'dev' drivers/gpu/drm/i915/i915_irq.c:2217: warning: No description found for parameter 'dev' drivers/gpu/drm/i915/i915_irq.c:2397: warning: No description found for parameter 'wedged' drivers/gpu/drm/i915/i915_irq.c:2397: warning: No description found for parameter 'fmt' include/drm/drm_crtc.h:310: warning: No description found for parameter 'mode_blob' include/drm/drm_crtc.h:748: warning: No description found for parameter 'tile_blob_ptr' include/drm/drm_crtc.h:787: warning: No description found for parameter 'rotation' include/drm/drm_crtc.h:883: warning: No description found for parameter 'mutex' include/drm/drm_crtc.h:883: warning: No description found for parameter 'helper_private' include/drm/drm_crtc.h:931: warning: Excess struct/union/enum/typedef member 'base' description in 'drm_bridge' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'tile_idr' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'delayed_event' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'edid_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'dpms_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'path_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'tile_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'plane_type_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'rotation_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'prop_src_x' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'prop_src_y' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'prop_src_w' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'prop_src_h' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'prop_crtc_x' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'prop_crtc_y' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'prop_crtc_w' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'prop_crtc_h' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'prop_fb_id' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'prop_crtc_id' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'prop_active' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'prop_mode_id' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'dvi_i_subconnector_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'dvi_i_select_subconnector_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'tv_subconnector_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'tv_select_subconnector_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'tv_mode_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'tv_left_margin_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'tv_right_margin_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'tv_top_margin_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'tv_bottom_margin_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'tv_brightness_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'tv_contrast_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'tv_flicker_reduction_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'tv_overscan_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'tv_saturation_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'tv_hue_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'scaling_mode_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'aspect_ratio_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'dirty_info_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'suggested_x_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'suggested_y_property' include/drm/drm_crtc.h:1169: warning: No description found for parameter 'allow_fb_modifiers' Warning(include/drm/drm_modeset_lock.h:47): Incorrect use of kernel-doc format: * Contended lock: if a lock is contended you should only call Warning(include/drm/drm_modeset_lock.h:54): Incorrect use of kernel-doc format: * list of held locks (drm_modeset_lock) Warning(include/drm/drm_modeset_lock.h:59): Incorrect use of kernel-doc format: * Trylock mode, use only for panic handlers! Warning(include/drm/drm_modeset_lock.h:74): Incorrect use of kernel-doc format: * modeset lock Warning(include/drm/drm_modeset_lock.h:79): Incorrect use of kernel-doc format: * Resources that are locked as part of an atomic update are added include/drm/drm_dp_helper.h:706: warning: No description found for parameter 'i2c_nack_count' include/drm/drm_dp_helper.h:706: warning: No description found for parameter 'i2c_defer_count' drivers/gpu/drm/drm_dp_mst_topology.c:2226: warning: No description found for parameter 'connector' include/drm/drm_dp_mst_helper.h:97: warning: No description found for parameter 'cached_edid' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'max_dpcd_transaction_bytes' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'sink_count' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'total_slots' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'avail_slots' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'total_pbn' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'qlock' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'tx_msg_downq' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'tx_msg_upq' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'tx_down_in_progress' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'tx_up_in_progress' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'payload_lock' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'proposed_vcpis' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'payloads' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'payload_mask' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'vcpi_mask' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'tx_waitq' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'work' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'tx_work' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'destroy_connector_list' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'destroy_connector_lock' include/drm/drm_dp_mst_helper.h:471: warning: No description found for parameter 'destroy_connector_work' drivers/gpu/drm/drm_dp_mst_topology.c:2226: warning: No description found for parameter 'connector'
include/drm/drm_mipi_dsi.h:104: warning: No description found for parameter 'list'
include/drm/drmP.h:164: warning: No description found for parameter 'fmt' include/drm/drmP.h:180: warning: No description found for parameter 'fmt' include/drm/drmP.h:198: warning: No description found for parameter 'fmt' include/drm/drmP.h:238: warning: No description found for parameter 'dev' include/drm/drmP.h:238: warning: No description found for parameter 'data' include/drm/drmP.h:238: warning: No description found for parameter 'file_priv' include/drm/drmP.h:271: warning: No description found for parameter 'ioctl' include/drm/drmP.h:271: warning: No description found for parameter '_func' include/drm/drmP.h:271: warning: No description found for parameter '_flags' include/drm/drmP.h:344: warning: cannot understand function prototype: 'struct drm_lock_data ' include/drm/drmP.h:397: warning: cannot understand function prototype: 'struct drm_driver ' include/drm/drmP.h:646: warning: cannot understand function prototype: 'struct drm_info_list ' include/drm/drmP.h:656: warning: cannot understand function prototype: 'struct drm_info_node ' include/drm/drmP.h:666: warning: cannot understand function prototype: 'struct drm_minor ' include/drm/drmP.h:712: warning: cannot understand function prototype: 'struct drm_device ' drivers/gpu/drm/i915/i915_irq.c:491: warning: No description found for parameter 'dev' drivers/gpu/drm/i915/i915_irq.c:2217: warning: No description found for parameter 'dev' drivers/gpu/drm/i915/i915_irq.c:2397: warning: No description found for parameter 'wedged' drivers/gpu/drm/i915/i915_irq.c:2397: warning: No description found for parameter 'fmt' drivers/gpu/drm/i915/i915_irq.c:491: warning: No description found for parameter 'dev' drivers/gpu/drm/i915/i915_irq.c:2217: warning: No description found for parameter 'dev' drivers/gpu/drm/i915/i915_irq.c:2397: warning: No description found for parameter 'wedged' drivers/gpu/drm/i915/i915_irq.c:2397: warning: No description found for parameter 'fmt' drivers/gpu/drm/i915/i915_irq.c:491: warning: No description found for parameter 'dev' drivers/gpu/drm/i915/i915_irq.c:2217: warning: No description found for parameter 'dev' drivers/gpu/drm/i915/i915_irq.c:2397: warning: No description found for parameter 'wedged' drivers/gpu/drm/i915/i915_irq.c:2397: warning: No description found for parameter 'fmt' drivers/gpu/drm/i915/i915_irq.c:491: warning: No description found for parameter 'dev' drivers/gpu/drm/i915/i915_irq.c:2217: warning: No description found for parameter 'dev' drivers/gpu/drm/i915/i915_irq.c:2397: warning: No description found for parameter 'wedged' drivers/gpu/drm/i915/i915_irq.c:2397: warning: No description found for parameter 'fmt' drivers/gpu/drm/i915/i915_gem.c:421: warning: No description found for parameter 'dev' drivers/gpu/drm/i915/i915_gem.c:421: warning: No description found for parameter 'data' drivers/gpu/drm/i915/i915_gem.c:421: warning: No description found for parameter 'file' drivers/gpu/drm/i915/i915_gem.c:686: warning: No description found for parameter 'dev' drivers/gpu/drm/i915/i915_gem.c:686: warning: No description found for parameter 'data' drivers/gpu/drm/i915/i915_gem.c:686: warning: No description found for parameter 'file' drivers/gpu/drm/i915/i915_gem.c:767: warning: No description found for parameter 'dev' drivers/gpu/drm/i915/i915_gem.c:767: warning: No description found for parameter 'obj' drivers/gpu/drm/i915/i915_gem.c:767: warning: No description found for parameter 'args' drivers/gpu/drm/i915/i915_gem.c:767: warning: No description found for parameter 'file' drivers/gpu/drm/i915/i915_gem.c:1027: warning: No description found for parameter 'dev' drivers/gpu/drm/i915/i915_gem.c:1027: warning: No description found for parameter 'data' drivers/gpu/drm/i915/i915_gem.c:1027: warning: No description found for parameter 'file' drivers/gpu/drm/i915/i915_gem.c:1192: warning: No description found for parameter 'rps' drivers/gpu/drm/i915/i915_gem.c:1398: warning: No description found for parameter 'req' drivers/gpu/drm/i915/i915_gem.c:1433: warning: No description found for parameter 'obj' drivers/gpu/drm/i915/i915_gem.c:1433: warning: No description found for parameter 'readonly' drivers/gpu/drm/i915/i915_gem.c:1556: warning: No description found for parameter 'dev' drivers/gpu/drm/i915/i915_gem.c:1556: warning: No description found for parameter 'data' drivers/gpu/drm/i915/i915_gem.c:1556: warning: No description found for parameter 'file' drivers/gpu/drm/i915/i915_gem.c:1619: warning: No description found for parameter 'dev' drivers/gpu/drm/i915/i915_gem.c:1619: warning: No description found for parameter 'data' drivers/gpu/drm/i915/i915_gem.c:1619: warning: No description found for parameter 'file' drivers/gpu/drm/i915/i915_gem.c:1664: warning: No description found for parameter 'dev' drivers/gpu/drm/i915/i915_gem.c:1664: warning: No description found for parameter 'data' drivers/gpu/drm/i915/i915_gem.c:1664: warning: No description found for parameter 'file' drivers/gpu/drm/i915/i915_gem.c:1729: warning: No description found for parameter 'vma' drivers/gpu/drm/i915/i915_gem.c:1729: warning: No description found for parameter 'vmf' drivers/gpu/drm/i915/i915_gem.c:1952: warning: No description found for parameter 'dev' drivers/gpu/drm/i915/i915_gem.c:1952: warning: No description found for parameter 'size' drivers/gpu/drm/i915/i915_gem.c:1952: warning: No description found for parameter 'tiling_mode' drivers/gpu/drm/i915/i915_gem.c:1952: warning: No description found for parameter 'fenced' drivers/gpu/drm/i915/i915_gem.c:1952: warning: Excess function parameter 'obj' description in 'i915_gem_get_gtt_alignment' drivers/gpu/drm/i915/i915_gem.c:2815: warning: No description found for parameter 'ring' drivers/gpu/drm/i915/i915_gem.c:2944: warning: No description found for parameter 'obj' drivers/gpu/drm/i915/i915_gem.c:2994: warning: No description found for parameter 'dev' drivers/gpu/drm/i915/i915_gem.c:2994: warning: No description found for parameter 'data' drivers/gpu/drm/i915/i915_gem.c:2994: warning: No description found for parameter 'file' drivers/gpu/drm/i915/i915_gem.c:2994: warning: Excess function parameter 'DRM_IOCTL_ARGS' description in 'i915_gem_wait_ioctl' drivers/gpu/drm/i915/i915_gem.c:3355: warning: No description found for parameter 'obj' drivers/gpu/drm/i915/i915_gem.c:3355: warning: No description found for parameter 'vm' drivers/gpu/drm/i915/i915_gem.c:3355: warning: No description found for parameter 'ggtt_view' drivers/gpu/drm/i915/i915_gem.c:3355: warning: No description found for parameter 'alignment' drivers/gpu/drm/i915/i915_gem.c:3355: warning: No description found for parameter 'flags' drivers/gpu/drm/i915/i915_gem.c:3576: warning: No description found for parameter 'obj' drivers/gpu/drm/i915/i915_gem.c:3576: warning: No description found for parameter 'write' drivers/gpu/drm/i915/i915_gem.c:3858: warning: No description found for parameter 'obj' drivers/gpu/drm/i915/i915_gem.c:3858: warning: No description found for parameter 'write' drivers/gpu/drm/i915/i915_gem.c:4962: warning: No description found for parameter 'old' drivers/gpu/drm/i915/i915_gem.c:4962: warning: No description found for parameter 'new' drivers/gpu/drm/i915/i915_gem.c:4962: warning: No description found for parameter 'frontbuffer_bits' drivers/gpu/drm/i915/intel_lrc.c:782: warning: No description found for parameter 'req' drivers/gpu/drm/i915/intel_lrc.c:782: warning: Excess function parameter 'request' description in 'intel_logical_ring_begin' drivers/gpu/drm/i915/intel_lrc.c:782: warning: Excess function parameter 'ctx' description in 'intel_logical_ring_begin' drivers/gpu/drm/i915/intel_lrc.c:837: warning: No description found for parameter 'params' drivers/gpu/drm/i915/intel_lrc.c:837: warning: Excess function parameter 'dev' description in 'intel_execlists_submission' drivers/gpu/drm/i915/intel_lrc.c:837: warning: Excess function parameter 'file' description in 'intel_execlists_submission' drivers/gpu/drm/i915/intel_lrc.c:837: warning: Excess function parameter 'ring' description in 'intel_execlists_submission' drivers/gpu/drm/i915/intel_lrc.c:837: warning: Excess function parameter 'ctx' description in 'intel_execlists_submission' drivers/gpu/drm/i915/intel_lrc.c:837: warning: Excess function parameter 'batch_obj' description in 'intel_execlists_submission' drivers/gpu/drm/i915/intel_lrc.c:837: warning: Excess function parameter 'exec_start' description in 'intel_execlists_submission' drivers/gpu/drm/i915/intel_lrc.c:837: warning: Excess function parameter 'dispatch_flags' description in 'intel_execlists_submission' drivers/gpu/drm/i915/intel_lrc.c:782: warning: No description found for parameter 'req' drivers/gpu/drm/i915/intel_lrc.c:782: warning: Excess function parameter 'request' description in 'intel_logical_ring_begin' drivers/gpu/drm/i915/intel_lrc.c:782: warning: Excess function parameter 'ctx' description in 'intel_logical_ring_begin' drivers/gpu/drm/i915/intel_lrc.c:837: warning: No description found for parameter 'params' drivers/gpu/drm/i915/intel_lrc.c:837: warning: Excess function parameter 'dev' description in 'intel_execlists_submission' drivers/gpu/drm/i915/intel_lrc.c:837: warning: Excess function parameter 'file' description in 'intel_execlists_submission' drivers/gpu/drm/i915/intel_lrc.c:837: warning: Excess function parameter 'ring' description in 'intel_execlists_submission'
vim +/list +104 include/drm/drm_mipi_dsi.h
068a0023 Andrzej Hajda 2013-12-04 88 struct mipi_dsi_device *dsi); 068a0023 Andrzej Hajda 2013-12-04 89 int (*detach)(struct mipi_dsi_host *host, 068a0023 Andrzej Hajda 2013-12-04 90 struct mipi_dsi_device *dsi); 068a0023 Andrzej Hajda 2013-12-04 91 ssize_t (*transfer)(struct mipi_dsi_host *host, ed6ff40e Thierry Reding 2014-08-05 92 const struct mipi_dsi_msg *msg); 068a0023 Andrzej Hajda 2013-12-04 93 }; 068a0023 Andrzej Hajda 2013-12-04 94 068a0023 Andrzej Hajda 2013-12-04 95 /** 068a0023 Andrzej Hajda 2013-12-04 96 * struct mipi_dsi_host - DSI host device 068a0023 Andrzej Hajda 2013-12-04 97 * @dev: driver model device node for this DSI host 068a0023 Andrzej Hajda 2013-12-04 98 * @ops: DSI host operations 068a0023 Andrzej Hajda 2013-12-04 99 */ 068a0023 Andrzej Hajda 2013-12-04 100 struct mipi_dsi_host { 068a0023 Andrzej Hajda 2013-12-04 101 struct device *dev; 068a0023 Andrzej Hajda 2013-12-04 102 const struct mipi_dsi_host_ops *ops; b3e0f8f8 Archit Taneja 2015-10-06 103 struct list_head list; 068a0023 Andrzej Hajda 2013-12-04 @104 }; 068a0023 Andrzej Hajda 2013-12-04 105 068a0023 Andrzej Hajda 2013-12-04 106 int mipi_dsi_host_register(struct mipi_dsi_host *host); 068a0023 Andrzej Hajda 2013-12-04 107 void mipi_dsi_host_unregister(struct mipi_dsi_host *host); b3e0f8f8 Archit Taneja 2015-10-06 108 struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node); 068a0023 Andrzej Hajda 2013-12-04 109 068a0023 Andrzej Hajda 2013-12-04 110 /* DSI mode flags */ 068a0023 Andrzej Hajda 2013-12-04 111 068a0023 Andrzej Hajda 2013-12-04 112 /* video mode */
:::::: The code at line 104 was first introduced by commit :::::: 068a00233969833f1ba925e7627797489efd6041 drm: Add MIPI DSI bus support
:::::: TO: Andrzej Hajda a.hajda@samsung.com :::::: CC: Thierry Reding treding@nvidia.com
--- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
On 10/06/2015 11:24 AM, Archit Taneja wrote:
mipi_dsi_devices are inherently aware of their host because they share a parent-child hierarchy in the device tree.
Non-dsi drivers that create a dummy dsi device don't have this data. In order to get this information, they require to a phandle to the dsi host in the device tree.
Maintain a list of all the hosts DSI that are currently registered.
This list will be used to find the mipi_dsi_host corresponding to the device_node passed in of_find_mipi_dsi_host_by_node.
Signed-off-by: Archit Taneja architt@codeaurora.org
Looks OK, beside lack of documentation, after fixing it you can add Reviewed-by: Andrzej Hajda a.hajda@samsung.com
Regards Andrzej
drivers/gpu/drm/drm_mipi_dsi.c | 30 ++++++++++++++++++++++++++++++ include/drm/drm_mipi_dsi.h | 2 ++ 2 files changed, 32 insertions(+)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index cbb7373..c51d73e 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -216,6 +216,28 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) return mipi_dsi_device_new(host, &info); }
+static DEFINE_MUTEX(host_lock); +static LIST_HEAD(host_list);
+struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node) +{
- struct mipi_dsi_host *host;
- mutex_lock(&host_lock);
- list_for_each_entry(host, &host_list, list) {
if (host->dev->of_node == node) {
mutex_unlock(&host_lock);
return host;
}
- }
- mutex_unlock(&host_lock);
- return NULL;
+} +EXPORT_SYMBOL(of_find_mipi_dsi_host_by_node);
int mipi_dsi_host_register(struct mipi_dsi_host *host) { struct device_node *node; @@ -227,6 +249,10 @@ int mipi_dsi_host_register(struct mipi_dsi_host *host) of_mipi_dsi_device_add(host, node); }
- mutex_lock(&host_lock);
- list_add_tail(&host->list, &host_list);
- mutex_unlock(&host_lock);
- return 0;
} EXPORT_SYMBOL(mipi_dsi_host_register); @@ -243,6 +269,10 @@ static int mipi_dsi_remove_device_fn(struct device *dev, void *priv) void mipi_dsi_host_unregister(struct mipi_dsi_host *host) { device_for_each_child(host->dev, NULL, mipi_dsi_remove_device_fn);
- mutex_lock(&host_lock);
- list_del_init(&host->list);
- mutex_unlock(&host_lock);
} EXPORT_SYMBOL(mipi_dsi_host_unregister);
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 68f49f4..15d3068 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -100,10 +100,12 @@ struct mipi_dsi_host_ops { struct mipi_dsi_host { struct device *dev; const struct mipi_dsi_host_ops *ops;
- struct list_head list;
};
int mipi_dsi_host_register(struct mipi_dsi_host *host); void mipi_dsi_host_unregister(struct mipi_dsi_host *host); +struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node);
/* DSI mode flags */
On 11/02/2015 04:20 PM, Andrzej Hajda wrote:
On 10/06/2015 11:24 AM, Archit Taneja wrote:
mipi_dsi_devices are inherently aware of their host because they share a parent-child hierarchy in the device tree.
Non-dsi drivers that create a dummy dsi device don't have this data. In order to get this information, they require to a phandle to the dsi host in the device tree.
Maintain a list of all the hosts DSI that are currently registered.
This list will be used to find the mipi_dsi_host corresponding to the device_node passed in of_find_mipi_dsi_host_by_node.
Signed-off-by: Archit Taneja architt@codeaurora.org
Looks OK, beside lack of documentation, after fixing it you can add Reviewed-by: Andrzej Hajda a.hajda@samsung.com
I will add missing documentation before posting v3.
Thanks again for the review.
Archit
Regards Andrzej
drivers/gpu/drm/drm_mipi_dsi.c | 30 ++++++++++++++++++++++++++++++ include/drm/drm_mipi_dsi.h | 2 ++ 2 files changed, 32 insertions(+)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index cbb7373..c51d73e 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -216,6 +216,28 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) return mipi_dsi_device_new(host, &info); }
+static DEFINE_MUTEX(host_lock); +static LIST_HEAD(host_list);
+struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node) +{
- struct mipi_dsi_host *host;
- mutex_lock(&host_lock);
- list_for_each_entry(host, &host_list, list) {
if (host->dev->of_node == node) {
mutex_unlock(&host_lock);
return host;
}
- }
- mutex_unlock(&host_lock);
- return NULL;
+} +EXPORT_SYMBOL(of_find_mipi_dsi_host_by_node);
- int mipi_dsi_host_register(struct mipi_dsi_host *host) { struct device_node *node;
@@ -227,6 +249,10 @@ int mipi_dsi_host_register(struct mipi_dsi_host *host) of_mipi_dsi_device_add(host, node); }
- mutex_lock(&host_lock);
- list_add_tail(&host->list, &host_list);
- mutex_unlock(&host_lock);
- return 0; } EXPORT_SYMBOL(mipi_dsi_host_register);
@@ -243,6 +269,10 @@ static int mipi_dsi_remove_device_fn(struct device *dev, void *priv) void mipi_dsi_host_unregister(struct mipi_dsi_host *host) { device_for_each_child(host->dev, NULL, mipi_dsi_remove_device_fn);
- mutex_lock(&host_lock);
- list_del_init(&host->list);
- mutex_unlock(&host_lock); } EXPORT_SYMBOL(mipi_dsi_host_unregister);
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 68f49f4..15d3068 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -100,10 +100,12 @@ struct mipi_dsi_host_ops { struct mipi_dsi_host { struct device *dev; const struct mipi_dsi_host_ops *ops;
struct list_head list; };
int mipi_dsi_host_register(struct mipi_dsi_host *host); void mipi_dsi_host_unregister(struct mipi_dsi_host *host);
+struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node);
/* DSI mode flags */
We are currently restricted when it comes to supporting DSI on devices that have a non-DSI control bus. For example, DSI encoder chips are available in the market that are configured via i2c. Configuring their registers via DSI bus is either optional or not available at all.
These devices still need to pass DSI parameters (data lanes, mode flags etc) to the DSI host they are connected to. We don't have a way to do that at the moment.
After some discussions on the previous RFC[1], we decided to support this by providing additional API in drm_mipi_dsi which lets us create new DSI devices without the need of them to have a DT node.
[1]: https://lkml.org/lkml/2015/6/30/42
Changes from v2 to v3:
- Incorporated misc comments by Andrzej. Changed from RFC to a PATCH set. - Fixed htmldocs warnings.
Archit Taneja (5): drm/dsi: Refactor device creation drm/dsi: Try to match non-DT dsi devices drm/dsi: Check for used channels drm/dsi: Add routine to unregister dsi device drm/dsi: Get DSI host by DT device node
drivers/gpu/drm/drm_mipi_dsi.c | 136 +++++++++++++++++++++++++++++++---------- include/drm/drm_mipi_dsi.h | 29 +++++++++ 2 files changed, 133 insertions(+), 32 deletions(-)
Simplify the mipi dsi device creation process. device_initialize and device_add don't need to be called separately when creating mipi_dsi_device's. Use device_register instead to simplify things.
Create a helper function mipi_dsi_device_new which takes in struct mipi_dsi_device_info and mipi_dsi_host. It clubs the functions mipi_dsi_device_alloc and mipi_dsi_device_add into one.
mipi_dsi_device_info acts as a template to populate the dsi device information. This is populated by of_mipi_dsi_device_add and passed to mipi_dsi_device_new.
Later on, we'll provide mipi_dsi_device_new as a standalone way to create a dsi device not available via DT.
The new device creation process tries to closely follow what's been done in i2c_new_device in i2c-core.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 61 +++++++++++++++++------------------------- include/drm/drm_mipi_dsi.h | 15 +++++++++++ 2 files changed, 40 insertions(+), 36 deletions(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 2d5ca8ee..82bcdcd 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -102,9 +102,18 @@ static const struct device_type mipi_dsi_device_type = { .release = mipi_dsi_dev_release, };
-static struct mipi_dsi_device *mipi_dsi_device_alloc(struct mipi_dsi_host *host) +struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, + struct mipi_dsi_device_info *info) { struct mipi_dsi_device *dsi; + struct device *dev = host->dev; + int ret; + + if (info->reg > 3) { + dev_err(dev, "device node has invalid reg property: %u\n", + info->reg); + return ERR_PTR(-EINVAL); + }
dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); if (!dsi) @@ -114,26 +123,27 @@ static struct mipi_dsi_device *mipi_dsi_device_alloc(struct mipi_dsi_host *host) dsi->dev.bus = &mipi_dsi_bus_type; dsi->dev.parent = host->dev; dsi->dev.type = &mipi_dsi_device_type; + dsi->dev.of_node = info->node; + dsi->channel = info->reg;
- device_initialize(&dsi->dev); - - return dsi; -} - -static int mipi_dsi_device_add(struct mipi_dsi_device *dsi) -{ - struct mipi_dsi_host *host = dsi->host; + dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), info->reg);
- dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), dsi->channel); + ret = device_register(&dsi->dev); + if (ret) { + dev_err(dev, "failed to register device: %d\n", ret); + kfree(dsi); + return ERR_PTR(ret); + }
- return device_add(&dsi->dev); + return dsi; } +EXPORT_SYMBOL(mipi_dsi_device_new);
static struct mipi_dsi_device * of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) { - struct mipi_dsi_device *dsi; struct device *dev = host->dev; + struct mipi_dsi_device_info info = { }; int ret; u32 reg;
@@ -144,31 +154,10 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) return ERR_PTR(-EINVAL); }
- if (reg > 3) { - dev_err(dev, "device node %s has invalid reg property: %u\n", - node->full_name, reg); - return ERR_PTR(-EINVAL); - } - - dsi = mipi_dsi_device_alloc(host); - if (IS_ERR(dsi)) { - dev_err(dev, "failed to allocate DSI device %s: %ld\n", - node->full_name, PTR_ERR(dsi)); - return dsi; - } - - dsi->dev.of_node = of_node_get(node); - dsi->channel = reg; + info.reg = reg; + info.node = of_node_get(node);
- ret = mipi_dsi_device_add(dsi); - if (ret) { - dev_err(dev, "failed to add DSI device %s: %d\n", - node->full_name, ret); - kfree(dsi); - return ERR_PTR(ret); - } - - return dsi; + return mipi_dsi_device_new(host, &info); }
int mipi_dsi_host_register(struct mipi_dsi_host *host) diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index f1d8d0d..90f4f3c 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -140,6 +140,19 @@ enum mipi_dsi_pixel_format { };
/** + * struct mipi_dsi_device_info - template for creating a mipi_dsi_device + * @reg: DSI virtual channel assigned to peripheral + * @node: pointer to OF device node + * + * This is populated and passed to mipi_dsi_device_new to create a new + * DSI device + */ +struct mipi_dsi_device_info { + u32 reg; + struct device_node *node; +}; + +/** * struct mipi_dsi_device - DSI peripheral device * @host: DSI host for this peripheral * @dev: driver model device node for this peripheral @@ -174,6 +187,8 @@ ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload, ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params, size_t num_params, void *data, size_t size);
+struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, + struct mipi_dsi_device_info *info); /** * enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode * @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking
Add a device name field in mipi_dsi_device. This name is different from the actual dev name (which is of the format "hostname.reg"). When the device is created via DT, this name is set to the modalias string. In the non-DT case, the driver creating the DSI device provides the name by populating a filed in mipi_dsi_device_info.
Matching for DT case would be as it was before. For the non-DT case, we compare the device and driver names. Other buses (like i2c/spi) perform a non-DT match by comparing the device name and entries in the driver's id_table. Such a mechanism isn't used for the dsi bus.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 25 ++++++++++++++++++++++++- include/drm/drm_mipi_dsi.h | 6 ++++++ 2 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 82bcdcd..143cce4 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -45,9 +45,26 @@ * subset of the MIPI DCS command set. */
+static const struct device_type mipi_dsi_device_type; + static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv) { - return of_driver_match_device(dev, drv); + struct mipi_dsi_device *dsi; + + if (dev->type == &mipi_dsi_device_type) + dsi = to_mipi_dsi_device(dev); + else + return 0; + + /* attempt OF style match */ + if (of_driver_match_device(dev, drv)) + return 1; + + /* compare dsi device and driver names */ + if (!strcmp(dsi->name, drv->name)) + return 1; + + return 0; }
static const struct dev_pm_ops mipi_dsi_device_pm_ops = { @@ -125,6 +142,7 @@ struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, dsi->dev.type = &mipi_dsi_device_type; dsi->dev.of_node = info->node; dsi->channel = info->reg; + strlcpy(dsi->name, info->type, sizeof(dsi->name));
dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), info->reg);
@@ -147,6 +165,11 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) int ret; u32 reg;
+ if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { + dev_err(dev, "modalias failure on %s\n", node->full_name); + return ERR_PTR(-EINVAL); + } + ret = of_property_read_u32(node, "reg", ®); if (ret) { dev_err(dev, "device node %s has no valid reg property: %d\n", diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 90f4f3c..cb084af 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -139,8 +139,11 @@ enum mipi_dsi_pixel_format { MIPI_DSI_FMT_RGB565, };
+#define DSI_DEV_NAME_SIZE 20 + /** * struct mipi_dsi_device_info - template for creating a mipi_dsi_device + * @type: dsi peripheral chip type * @reg: DSI virtual channel assigned to peripheral * @node: pointer to OF device node * @@ -148,6 +151,7 @@ enum mipi_dsi_pixel_format { * DSI device */ struct mipi_dsi_device_info { + char type[DSI_DEV_NAME_SIZE]; u32 reg; struct device_node *node; }; @@ -156,6 +160,7 @@ struct mipi_dsi_device_info { * struct mipi_dsi_device - DSI peripheral device * @host: DSI host for this peripheral * @dev: driver model device node for this peripheral + * @name: dsi peripheral chip type * @channel: virtual channel assigned to the peripheral * @format: pixel format for video mode * @lanes: number of active data lanes @@ -165,6 +170,7 @@ struct mipi_dsi_device { struct mipi_dsi_host *host; struct device dev;
+ char name[DSI_DEV_NAME_SIZE]; unsigned int channel; unsigned int lanes; enum mipi_dsi_pixel_format format;
Hi Archit,
[auto build test ERROR on: v4.4-rc3] [also build test ERROR on: next-20151127]
url: https://github.com/0day-ci/linux/commits/Archit-Taneja/drm-dsi-DSI-for-devic... config: x86_64-allyesdebian (attached as .config) reproduce: # save the attached .config to linux build tree make ARCH=x86_64
All errors (new ones prefixed by >>):
drivers/gpu/drm/drm_mipi_dsi.c: In function 'of_mipi_dsi_device_add':
drivers/gpu/drm/drm_mipi_dsi.c:168:6: error: implicit declaration of function 'of_modalias_node' [-Werror=implicit-function-declaration]
if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { ^ cc1: some warnings being treated as errors
vim +/of_modalias_node +168 drivers/gpu/drm/drm_mipi_dsi.c
162 { 163 struct device *dev = host->dev; 164 struct mipi_dsi_device_info info = { }; 165 int ret; 166 u32 reg; 167
168 if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
169 dev_err(dev, "modalias failure on %s\n", node->full_name); 170 return ERR_PTR(-EINVAL); 171 }
--- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi,
On 11/30/2015 06:15 PM, kbuild test robot wrote:
Hi Archit,
[auto build test ERROR on: v4.4-rc3] [also build test ERROR on: next-20151127]
url: https://github.com/0day-ci/linux/commits/Archit-Taneja/drm-dsi-DSI-for-devic... config: x86_64-allyesdebian (attached as .config) reproduce: # save the attached .config to linux build tree make ARCH=x86_64
All errors (new ones prefixed by >>):
drivers/gpu/drm/drm_mipi_dsi.c: In function 'of_mipi_dsi_device_add':
drivers/gpu/drm/drm_mipi_dsi.c:168:6: error: implicit declaration of function 'of_modalias_node' [-Werror=implicit-function-declaration]
if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
Any suggestions on how to fix this? Is it ok to make DRM_MIPI_DSI depend on CONFIG_OF? Or is it better to wrap these funcs around IF_ENABLED(CONFIG_OF)?
Archit
^ cc1: some warnings being treated as errors
vim +/of_modalias_node +168 drivers/gpu/drm/drm_mipi_dsi.c
162 { 163 struct device *dev = host->dev; 164 struct mipi_dsi_device_info info = { }; 165 int ret; 166 u32 reg; 167
168 if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
169 dev_err(dev, "modalias failure on %s\n", node->full_name); 170 return ERR_PTR(-EINVAL); 171 }
0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
On Mon, 07 Dec 2015, Archit Taneja architt@codeaurora.org wrote:
Hi,
On 11/30/2015 06:15 PM, kbuild test robot wrote:
Hi Archit,
[auto build test ERROR on: v4.4-rc3] [also build test ERROR on: next-20151127]
url: https://github.com/0day-ci/linux/commits/Archit-Taneja/drm-dsi-DSI-for-devic... config: x86_64-allyesdebian (attached as .config) reproduce: # save the attached .config to linux build tree make ARCH=x86_64
All errors (new ones prefixed by >>):
drivers/gpu/drm/drm_mipi_dsi.c: In function 'of_mipi_dsi_device_add':
drivers/gpu/drm/drm_mipi_dsi.c:168:6: error: implicit declaration of function 'of_modalias_node' [-Werror=implicit-function-declaration]
if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
Any suggestions on how to fix this? Is it ok to make DRM_MIPI_DSI depend on CONFIG_OF?
Please don't.
BR, Jani.
On 12/07/2015 02:15 PM, Jani Nikula wrote:
On Mon, 07 Dec 2015, Archit Taneja architt@codeaurora.org wrote:
Hi,
On 11/30/2015 06:15 PM, kbuild test robot wrote:
Hi Archit,
[auto build test ERROR on: v4.4-rc3] [also build test ERROR on: next-20151127]
url: https://github.com/0day-ci/linux/commits/Archit-Taneja/drm-dsi-DSI-for-devic... config: x86_64-allyesdebian (attached as .config) reproduce: # save the attached .config to linux build tree make ARCH=x86_64
All errors (new ones prefixed by >>):
drivers/gpu/drm/drm_mipi_dsi.c: In function 'of_mipi_dsi_device_add':
drivers/gpu/drm/drm_mipi_dsi.c:168:6: error: implicit declaration of function 'of_modalias_node' [-Werror=implicit-function-declaration]
if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
Any suggestions on how to fix this? Is it ok to make DRM_MIPI_DSI depend on CONFIG_OF?
Please don't.
Just curious, how did x86 use DSI if the only way to create DSI devices until now was via DT?
Archit
BR, Jani.
On Mon, 07 Dec 2015, Archit Taneja architt@codeaurora.org wrote:
On 12/07/2015 02:15 PM, Jani Nikula wrote:
On Mon, 07 Dec 2015, Archit Taneja architt@codeaurora.org wrote:
Hi,
On 11/30/2015 06:15 PM, kbuild test robot wrote:
Hi Archit,
[auto build test ERROR on: v4.4-rc3] [also build test ERROR on: next-20151127]
url: https://github.com/0day-ci/linux/commits/Archit-Taneja/drm-dsi-DSI-for-devic... config: x86_64-allyesdebian (attached as .config) reproduce: # save the attached .config to linux build tree make ARCH=x86_64
All errors (new ones prefixed by >>):
drivers/gpu/drm/drm_mipi_dsi.c: In function 'of_mipi_dsi_device_add':
drivers/gpu/drm/drm_mipi_dsi.c:168:6: error: implicit declaration of function 'of_modalias_node' [-Werror=implicit-function-declaration]
if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
Any suggestions on how to fix this? Is it ok to make DRM_MIPI_DSI depend on CONFIG_OF?
Please don't.
Just curious, how did x86 use DSI if the only way to create DSI devices until now was via DT?
Oh, you want the gory details... we use the DSI code as a library for abstraction and helpers, without actually creating or registering the devices.
BR, Jani.
Archit
BR, Jani.
On 12/07/2015 02:40 PM, Jani Nikula wrote:
On Mon, 07 Dec 2015, Archit Taneja architt@codeaurora.org wrote:
On 12/07/2015 02:15 PM, Jani Nikula wrote:
On Mon, 07 Dec 2015, Archit Taneja architt@codeaurora.org wrote:
Hi,
On 11/30/2015 06:15 PM, kbuild test robot wrote:
Hi Archit,
[auto build test ERROR on: v4.4-rc3] [also build test ERROR on: next-20151127]
url: https://github.com/0day-ci/linux/commits/Archit-Taneja/drm-dsi-DSI-for-devic... config: x86_64-allyesdebian (attached as .config) reproduce: # save the attached .config to linux build tree make ARCH=x86_64
All errors (new ones prefixed by >>):
drivers/gpu/drm/drm_mipi_dsi.c: In function 'of_mipi_dsi_device_add':
> drivers/gpu/drm/drm_mipi_dsi.c:168:6: error: implicit declaration of function 'of_modalias_node' [-Werror=implicit-function-declaration]
if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
Any suggestions on how to fix this? Is it ok to make DRM_MIPI_DSI depend on CONFIG_OF?
Please don't.
Just curious, how did x86 use DSI if the only way to create DSI devices until now was via DT?
Oh, you want the gory details... we use the DSI code as a library for abstraction and helpers, without actually creating or registering the devices.
Okay, got it. I'll go with the IS_ENABLED(CONFIG_OF) approach.
Humble request: Next time if I share something that doesn't make sense, please reply with something more than a "Please don't". That just sounds condescending and doesn't really help me with my cause either.
Thanks, Archit
BR, Jani.
Archit
BR, Jani.
On Mon, 07 Dec 2015, Archit Taneja architt@codeaurora.org wrote:
On 12/07/2015 02:40 PM, Jani Nikula wrote:
On Mon, 07 Dec 2015, Archit Taneja architt@codeaurora.org wrote:
On 12/07/2015 02:15 PM, Jani Nikula wrote:
On Mon, 07 Dec 2015, Archit Taneja architt@codeaurora.org wrote:
Any suggestions on how to fix this? Is it ok to make DRM_MIPI_DSI depend on CONFIG_OF?
Please don't.
Just curious, how did x86 use DSI if the only way to create DSI devices until now was via DT?
Oh, you want the gory details... we use the DSI code as a library for abstraction and helpers, without actually creating or registering the devices.
Okay, got it. I'll go with the IS_ENABLED(CONFIG_OF) approach.
Thanks, appreciated, so i915 doesn't need to depend on OF.
Humble request: Next time if I share something that doesn't make sense, please reply with something more than a "Please don't". That just sounds condescending and doesn't really help me with my cause either.
That's a fair request, no need to be humble about it. Apologies.
BR, Jani.
On Mon, Dec 7, 2015 at 3:45 AM, Jani Nikula jani.nikula@linux.intel.com wrote:
On Mon, 07 Dec 2015, Archit Taneja architt@codeaurora.org wrote:
Hi,
On 11/30/2015 06:15 PM, kbuild test robot wrote:
Hi Archit,
[auto build test ERROR on: v4.4-rc3] [also build test ERROR on: next-20151127]
url: https://github.com/0day-ci/linux/commits/Archit-Taneja/drm-dsi-DSI-for-devic... config: x86_64-allyesdebian (attached as .config) reproduce: # save the attached .config to linux build tree make ARCH=x86_64
All errors (new ones prefixed by >>):
drivers/gpu/drm/drm_mipi_dsi.c: In function 'of_mipi_dsi_device_add':
drivers/gpu/drm/drm_mipi_dsi.c:168:6: error: implicit declaration of function 'of_modalias_node' [-Werror=implicit-function-declaration]
if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
Any suggestions on how to fix this? Is it ok to make DRM_MIPI_DSI depend on CONFIG_OF?
Please don't.
I assume you are not using of_mipi_dsi_device_add()? We could just put this one fxn inside #ifdef CONFIG_OF / #endif, I think..
BR, -R
BR, Jani.
-- Jani Nikula, Intel Open Source Technology Center _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/dri-devel
We don't check whether a previously registered mipi_dsi_device under the same host shares the same virtual channel.
Before registering, check if any of the registered devices doesn't already have the same virtual channel.
This wasn't crucial when all the devices under a host were populated via DT. Now that we also support creating devices manually, we could end up in a situation where a driver tries to create a device with a virtual channel already taken by a device populated in DT.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 143cce4..f73e434 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -119,6 +119,22 @@ static const struct device_type mipi_dsi_device_type = { .release = mipi_dsi_dev_release, };
+static int __dsi_check_chan_busy(struct device *dev, void *data) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); + u32 *reg = data; + + if (dsi && dsi->channel == *reg) + return -EBUSY; + + return 0; +} + +static int mipi_dsi_check_chan_busy(struct mipi_dsi_host *host, u32 reg) +{ + return device_for_each_child(host->dev, ®, __dsi_check_chan_busy); +} + struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, struct mipi_dsi_device_info *info) { @@ -146,14 +162,20 @@ struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host,
dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), info->reg);
+ ret = mipi_dsi_check_chan_busy(host, info->reg); + if (ret) + goto err; + ret = device_register(&dsi->dev); if (ret) { dev_err(dev, "failed to register device: %d\n", ret); - kfree(dsi); - return ERR_PTR(ret); + goto err; }
return dsi; +err: + kfree(dsi); + return ERR_PTR(ret); } EXPORT_SYMBOL(mipi_dsi_device_new);
A driver calling mipi_dsi_device_new might want to unregister the device once it's done. It might also require it in an error handling path in case something didn't go right.
Signed-off-by: Archit Taneja architt@codeaurora.org --- include/drm/drm_mipi_dsi.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index cb084af..410d8b5 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -195,6 +195,11 @@ ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,
struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, struct mipi_dsi_device_info *info); +static inline void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi) +{ + device_unregister(&dsi->dev); +} + /** * enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode * @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking
On 11/30/2015 01:01 PM, Archit Taneja wrote:
A driver calling mipi_dsi_device_new might want to unregister the device once it's done. It might also require it in an error handling path in case something didn't go right.
Signed-off-by: Archit Taneja architt@codeaurora.org
Reviewed-by: Andrzej Hajda a.hajda@samsung.com
Regards Andrzej
mipi_dsi_devices are inherently aware of their host because they share a parent-child hierarchy in the device tree.
non-dsi drivers that create dsi device don't have this data. In order to get this information, they require to a phandle to the dsi host in the device tree.
Maintain a list of all the hosts DSI that are currently registered.
This list will be used to find the mipi_dsi_host corresponding to the device_node passed in of_find_mipi_dsi_host_by_node.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 38 ++++++++++++++++++++++++++++++++++++++ include/drm/drm_mipi_dsi.h | 3 +++ 2 files changed, 41 insertions(+)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index f73e434..e9c17e25 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -205,6 +205,36 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) return mipi_dsi_device_new(host, &info); }
+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 + * @node: device tree node + * + * Return: A pointer to the MIPI DSI host corresponding to @np or NULL if no + * such device exists (or has not been registered yet). + */ +struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node) +{ + struct mipi_dsi_host *host; + + mutex_lock(&host_lock); + + list_for_each_entry(host, &host_list, list) { + if (host->dev->of_node == node) { + mutex_unlock(&host_lock); + return host; + } + } + + mutex_unlock(&host_lock); + + return NULL; +} +EXPORT_SYMBOL(of_find_mipi_dsi_host_by_node); + int mipi_dsi_host_register(struct mipi_dsi_host *host) { struct device_node *node; @@ -216,6 +246,10 @@ int mipi_dsi_host_register(struct mipi_dsi_host *host) of_mipi_dsi_device_add(host, node); }
+ mutex_lock(&host_lock); + list_add_tail(&host->list, &host_list); + mutex_unlock(&host_lock); + return 0; } EXPORT_SYMBOL(mipi_dsi_host_register); @@ -232,6 +266,10 @@ static int mipi_dsi_remove_device_fn(struct device *dev, void *priv) void mipi_dsi_host_unregister(struct mipi_dsi_host *host) { device_for_each_child(host->dev, NULL, mipi_dsi_remove_device_fn); + + mutex_lock(&host_lock); + list_del_init(&host->list); + mutex_unlock(&host_lock); } EXPORT_SYMBOL(mipi_dsi_host_unregister);
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 410d8b5..e5c1df9 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -96,14 +96,17 @@ struct mipi_dsi_host_ops { * struct mipi_dsi_host - DSI host device * @dev: driver model device node for this DSI host * @ops: DSI host operations + * @list: list management */ struct mipi_dsi_host { struct device *dev; const struct mipi_dsi_host_ops *ops; + struct list_head list; };
int mipi_dsi_host_register(struct mipi_dsi_host *host); void mipi_dsi_host_unregister(struct mipi_dsi_host *host); +struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node);
/* DSI mode flags */
We are currently restricted when it comes to supporting DSI on devices that have a non-DSI control bus. For example, DSI encoder chips are available in the market that are configured via i2c. Configuring their registers via DSI bus is either optional or not available at all.
These devices still need to pass DSI parameters (data lanes, mode flags etc) to the DSI host they are connected to. We don't have a way to do that at the moment.
After some discussions on the previous RFC[1], we decided to support this by providing additional API in drm_mipi_dsi which lets us create new DSI devices without the need of them to have a DT node.
[1]: https://lkml.org/lkml/2015/6/30/42
Changes in v4: - Added a new patch that fixes build issues when CONFIG_OF is not set.
Changes in v3:
- Incorporated misc comments by Andrzej. Changed from RFC to a PATCH set. - Fixed htmldocs warnings.
Archit Taneja (6): drm/dsi: check for CONFIG_OF when defining of_mipi_dsi_device_add drm/dsi: Refactor device creation drm/dsi: Try to match non-DT dsi devices drm/dsi: Check for used channels drm/dsi: Add routine to unregister dsi device drm/dsi: Get DSI host by DT device node
drivers/gpu/drm/drm_mipi_dsi.c | 144 ++++++++++++++++++++++++++++++++--------- include/drm/drm_mipi_dsi.h | 29 +++++++++ 2 files changed, 141 insertions(+), 32 deletions(-)
of_mipi_dsi_device_add is used only when CONFIG_OF is enabled. It currently works if OF support is disabled, but this will change when we add more functionality to it.
Define the original func if CONFIG_OF is enabled. Define a dummy func otherwise.
Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 2d5ca8ee..bced235 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -129,6 +129,7 @@ static int mipi_dsi_device_add(struct mipi_dsi_device *dsi) return device_add(&dsi->dev); }
+#if IS_ENABLED(CONFIG_OF) static struct mipi_dsi_device * of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) { @@ -170,6 +171,13 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node)
return dsi; } +#else +static struct mipi_dsi_device * +of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) +{ + return NULL; +} +#endif
int mipi_dsi_host_register(struct mipi_dsi_host *host) {
On Thu, Dec 10, 2015 at 06:11:35PM +0530, Archit Taneja wrote:
of_mipi_dsi_device_add is used only when CONFIG_OF is enabled. It currently works if OF support is disabled, but this will change when we add more functionality to it.
Define the original func if CONFIG_OF is enabled. Define a dummy func otherwise.
Signed-off-by: Archit Taneja architt@codeaurora.org
drivers/gpu/drm/drm_mipi_dsi.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 2d5ca8ee..bced235 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -129,6 +129,7 @@ static int mipi_dsi_device_add(struct mipi_dsi_device *dsi) return device_add(&dsi->dev); }
+#if IS_ENABLED(CONFIG_OF) static struct mipi_dsi_device * of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) { @@ -170,6 +171,13 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node)
return dsi; } +#else +static struct mipi_dsi_device * +of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) +{
- return NULL;
+} +#endif
The OF implementation of this function never returns NULL, so perhaps this should return an ERR_PTR()-encoded error code instead? This isn't really important because we never check the return value in the one call-site that we have, which I guess could be an argument for removing the return value altogether...
Thierry
On 1/21/2016 9:01 PM, Thierry Reding wrote:
On Thu, Dec 10, 2015 at 06:11:35PM +0530, Archit Taneja wrote:
of_mipi_dsi_device_add is used only when CONFIG_OF is enabled. It currently works if OF support is disabled, but this will change when we add more functionality to it.
Define the original func if CONFIG_OF is enabled. Define a dummy func otherwise.
Signed-off-by: Archit Taneja architt@codeaurora.org
drivers/gpu/drm/drm_mipi_dsi.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 2d5ca8ee..bced235 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -129,6 +129,7 @@ static int mipi_dsi_device_add(struct mipi_dsi_device *dsi) return device_add(&dsi->dev); }
+#if IS_ENABLED(CONFIG_OF) static struct mipi_dsi_device * of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) { @@ -170,6 +171,13 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node)
return dsi; } +#else +static struct mipi_dsi_device * +of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) +{
- return NULL;
+} +#endif
The OF implementation of this function never returns NULL, so perhaps this should return an ERR_PTR()-encoded error code instead? This isn't really important because we never check the return value in the one call-site that we have, which I guess could be an argument for removing the return value altogether...
You're right. I'll replace this with ERR_PTR(-ENODEV). Maybe we could keep the return value in case we use it in the future.
Thanks, Archit
Thierry
Simplify the mipi dsi device creation process. device_initialize and device_add don't need to be called separately when creating mipi_dsi_device's. Use device_register instead to simplify things.
Create a helper function mipi_dsi_device_new which takes in struct mipi_dsi_device_info and mipi_dsi_host. It clubs the functions mipi_dsi_device_alloc and mipi_dsi_device_add into one.
mipi_dsi_device_info acts as a template to populate the dsi device information. This is populated by of_mipi_dsi_device_add and passed to mipi_dsi_device_new.
Later on, we'll provide mipi_dsi_device_new as a standalone way to create a dsi device not available via DT.
The new device creation process tries to closely follow what's been done in i2c_new_device in i2c-core.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 61 +++++++++++++++++------------------------- include/drm/drm_mipi_dsi.h | 15 +++++++++++ 2 files changed, 40 insertions(+), 36 deletions(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index bced235..9434585 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -102,9 +102,18 @@ static const struct device_type mipi_dsi_device_type = { .release = mipi_dsi_dev_release, };
-static struct mipi_dsi_device *mipi_dsi_device_alloc(struct mipi_dsi_host *host) +struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, + struct mipi_dsi_device_info *info) { struct mipi_dsi_device *dsi; + struct device *dev = host->dev; + int ret; + + if (info->reg > 3) { + dev_err(dev, "device node has invalid reg property: %u\n", + info->reg); + return ERR_PTR(-EINVAL); + }
dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); if (!dsi) @@ -114,27 +123,28 @@ static struct mipi_dsi_device *mipi_dsi_device_alloc(struct mipi_dsi_host *host) dsi->dev.bus = &mipi_dsi_bus_type; dsi->dev.parent = host->dev; dsi->dev.type = &mipi_dsi_device_type; + dsi->dev.of_node = info->node; + dsi->channel = info->reg;
- device_initialize(&dsi->dev); - - return dsi; -} - -static int mipi_dsi_device_add(struct mipi_dsi_device *dsi) -{ - struct mipi_dsi_host *host = dsi->host; + dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), info->reg);
- dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), dsi->channel); + ret = device_register(&dsi->dev); + if (ret) { + dev_err(dev, "failed to register device: %d\n", ret); + kfree(dsi); + return ERR_PTR(ret); + }
- return device_add(&dsi->dev); + return dsi; } +EXPORT_SYMBOL(mipi_dsi_device_new);
#if IS_ENABLED(CONFIG_OF) static struct mipi_dsi_device * of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) { - struct mipi_dsi_device *dsi; struct device *dev = host->dev; + struct mipi_dsi_device_info info = { }; int ret; u32 reg;
@@ -145,31 +155,10 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) return ERR_PTR(-EINVAL); }
- if (reg > 3) { - dev_err(dev, "device node %s has invalid reg property: %u\n", - node->full_name, reg); - return ERR_PTR(-EINVAL); - } - - dsi = mipi_dsi_device_alloc(host); - if (IS_ERR(dsi)) { - dev_err(dev, "failed to allocate DSI device %s: %ld\n", - node->full_name, PTR_ERR(dsi)); - return dsi; - } - - dsi->dev.of_node = of_node_get(node); - dsi->channel = reg; + info.reg = reg; + info.node = of_node_get(node);
- ret = mipi_dsi_device_add(dsi); - if (ret) { - dev_err(dev, "failed to add DSI device %s: %d\n", - node->full_name, ret); - kfree(dsi); - return ERR_PTR(ret); - } - - return dsi; + return mipi_dsi_device_new(host, &info); } #else static struct mipi_dsi_device * diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index f1d8d0d..90f4f3c 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -140,6 +140,19 @@ enum mipi_dsi_pixel_format { };
/** + * struct mipi_dsi_device_info - template for creating a mipi_dsi_device + * @reg: DSI virtual channel assigned to peripheral + * @node: pointer to OF device node + * + * This is populated and passed to mipi_dsi_device_new to create a new + * DSI device + */ +struct mipi_dsi_device_info { + u32 reg; + struct device_node *node; +}; + +/** * struct mipi_dsi_device - DSI peripheral device * @host: DSI host for this peripheral * @dev: driver model device node for this peripheral @@ -174,6 +187,8 @@ ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload, ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params, size_t num_params, void *data, size_t size);
+struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, + struct mipi_dsi_device_info *info); /** * enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode * @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking
On Thu, Dec 10, 2015 at 06:11:36PM +0530, Archit Taneja wrote:
Simplify the mipi dsi device creation process. device_initialize and
"MIPI" and "DSI", please.
device_add don't need to be called separately when creating mipi_dsi_device's. Use device_register instead to simplify things.
Create a helper function mipi_dsi_device_new which takes in struct mipi_dsi_device_info and mipi_dsi_host. It clubs the functions mipi_dsi_device_alloc and mipi_dsi_device_add into one.
mipi_dsi_device_info acts as a template to populate the dsi device information. This is populated by of_mipi_dsi_device_add and passed to mipi_dsi_device_new.
Later on, we'll provide mipi_dsi_device_new as a standalone way to create a dsi device not available via DT.
The new device creation process tries to closely follow what's been done in i2c_new_device in i2c-core.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org
drivers/gpu/drm/drm_mipi_dsi.c | 61 +++++++++++++++++------------------------- include/drm/drm_mipi_dsi.h | 15 +++++++++++ 2 files changed, 40 insertions(+), 36 deletions(-)
To be honest, I'm not sure I like this. If you want to have a simpler helper, why not implement it using the lower-level helpers. Really the only thing you're doing here is add a high-level helper that takes an info struct, whereas previously the same would be done by storing the info directly in the structure between allocation and addition of the device.
Initially the implementation was following that of platform devices, I see no reason to deviate from that. What you want here can easily be done by something like:
struct mipi_dsi_device * mipi_dsi_device_register_full(struct mipi_dsi_host *host, const struct mipi_dsi_device_info *info) { struct mipi_dsi_device *dsi;
dsi = mipi_dsi_device_alloc(host); if (IS_ERR(dsi)) return dsi;
dsi->dev.of_node = info->node; dsi->channel = info->channel;
err = mipi_dsi_device_add(dsi); if (err < 0) { ... }
return dsi; }
Thierry
On 1/21/2016 9:16 PM, Thierry Reding wrote:
On Thu, Dec 10, 2015 at 06:11:36PM +0530, Archit Taneja wrote:
Simplify the mipi dsi device creation process. device_initialize and
"MIPI" and "DSI", please.
Sure, I'll replace with these and in the other patches.
device_add don't need to be called separately when creating mipi_dsi_device's. Use device_register instead to simplify things.
Create a helper function mipi_dsi_device_new which takes in struct mipi_dsi_device_info and mipi_dsi_host. It clubs the functions mipi_dsi_device_alloc and mipi_dsi_device_add into one.
mipi_dsi_device_info acts as a template to populate the dsi device information. This is populated by of_mipi_dsi_device_add and passed to mipi_dsi_device_new.
Later on, we'll provide mipi_dsi_device_new as a standalone way to create a dsi device not available via DT.
The new device creation process tries to closely follow what's been done in i2c_new_device in i2c-core.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org
drivers/gpu/drm/drm_mipi_dsi.c | 61 +++++++++++++++++------------------------- include/drm/drm_mipi_dsi.h | 15 +++++++++++ 2 files changed, 40 insertions(+), 36 deletions(-)
To be honest, I'm not sure I like this. If you want to have a simpler helper, why not implement it using the lower-level helpers. Really the only thing you're doing here is add a high-level helper that takes an info struct, whereas previously the same would be done by storing the info directly in the structure between allocation and addition of the device.
Initially the implementation was following that of platform devices, I see no reason to deviate from that. What you want here can easily be
I don't see why we need to call device_initialize and device_add separately for DSI devices. From my (limited) understanding, we should call these separately if we want to take a reference (using get_device()), or set up some private data before the bus's notifier kicks in.
Since the main purpose of the series is not to simplify the device creation code, I can drop this.
done by something like:
struct mipi_dsi_device * mipi_dsi_device_register_full(struct mipi_dsi_host *host, const struct mipi_dsi_device_info *info) { struct mipi_dsi_device *dsi;
dsi = mipi_dsi_device_alloc(host); if (IS_ERR(dsi)) return dsi; dsi->dev.of_node = info->node; dsi->channel = info->channel; err = mipi_dsi_device_add(dsi); if (err < 0) { ... } return dsi;
}
Thierry
This does look less intrusive. I'll consider switching to this.
Thanks, Archit
Add a device name field in mipi_dsi_device. This name is different from the actual dev name (which is of the format "hostname.reg"). When the device is created via DT, this name is set to the modalias string. In the non-DT case, the driver creating the DSI device provides the name by populating a filed in mipi_dsi_device_info.
Matching for DT case would be as it was before. For the non-DT case, we compare the device and driver names. Other buses (like i2c/spi) perform a non-DT match by comparing the device name and entries in the driver's id_table. Such a mechanism isn't used for the dsi bus.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 25 ++++++++++++++++++++++++- include/drm/drm_mipi_dsi.h | 6 ++++++ 2 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 9434585..5a46802 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -45,9 +45,26 @@ * subset of the MIPI DCS command set. */
+static const struct device_type mipi_dsi_device_type; + static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv) { - return of_driver_match_device(dev, drv); + struct mipi_dsi_device *dsi; + + if (dev->type == &mipi_dsi_device_type) + dsi = to_mipi_dsi_device(dev); + else + return 0; + + /* attempt OF style match */ + if (of_driver_match_device(dev, drv)) + return 1; + + /* compare dsi device and driver names */ + if (!strcmp(dsi->name, drv->name)) + return 1; + + return 0; }
static const struct dev_pm_ops mipi_dsi_device_pm_ops = { @@ -125,6 +142,7 @@ struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, dsi->dev.type = &mipi_dsi_device_type; dsi->dev.of_node = info->node; dsi->channel = info->reg; + strlcpy(dsi->name, info->type, sizeof(dsi->name));
dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), info->reg);
@@ -148,6 +166,11 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) int ret; u32 reg;
+ if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { + dev_err(dev, "modalias failure on %s\n", node->full_name); + return ERR_PTR(-EINVAL); + } + ret = of_property_read_u32(node, "reg", ®); if (ret) { dev_err(dev, "device node %s has no valid reg property: %d\n", diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 90f4f3c..cb084af 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -139,8 +139,11 @@ enum mipi_dsi_pixel_format { MIPI_DSI_FMT_RGB565, };
+#define DSI_DEV_NAME_SIZE 20 + /** * struct mipi_dsi_device_info - template for creating a mipi_dsi_device + * @type: dsi peripheral chip type * @reg: DSI virtual channel assigned to peripheral * @node: pointer to OF device node * @@ -148,6 +151,7 @@ enum mipi_dsi_pixel_format { * DSI device */ struct mipi_dsi_device_info { + char type[DSI_DEV_NAME_SIZE]; u32 reg; struct device_node *node; }; @@ -156,6 +160,7 @@ struct mipi_dsi_device_info { * struct mipi_dsi_device - DSI peripheral device * @host: DSI host for this peripheral * @dev: driver model device node for this peripheral + * @name: dsi peripheral chip type * @channel: virtual channel assigned to the peripheral * @format: pixel format for video mode * @lanes: number of active data lanes @@ -165,6 +170,7 @@ struct mipi_dsi_device { struct mipi_dsi_host *host; struct device dev;
+ char name[DSI_DEV_NAME_SIZE]; unsigned int channel; unsigned int lanes; enum mipi_dsi_pixel_format format;
On Thu, Dec 10, 2015 at 06:11:37PM +0530, Archit Taneja wrote:
Add a device name field in mipi_dsi_device. This name is different from the actual dev name (which is of the format "hostname.reg"). When the device is created via DT, this name is set to the modalias string.
Why? What's the use of setting this to the modalias string?
In the non-DT case, the driver creating the DSI device provides the name by populating a filed in mipi_dsi_device_info.
Matching for DT case would be as it was before. For the non-DT case, we compare the device and driver names. Other buses (like i2c/spi)
"I2C" and "SPI", please.
perform a non-DT match by comparing the device name and entries in the driver's id_table. Such a mechanism isn't used for the dsi bus.
"DSI", please.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org
drivers/gpu/drm/drm_mipi_dsi.c | 25 ++++++++++++++++++++++++- include/drm/drm_mipi_dsi.h | 6 ++++++ 2 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 9434585..5a46802 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -45,9 +45,26 @@
- subset of the MIPI DCS command set.
*/
+static const struct device_type mipi_dsi_device_type;
static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv) {
- return of_driver_match_device(dev, drv);
- struct mipi_dsi_device *dsi;
- if (dev->type == &mipi_dsi_device_type)
dsi = to_mipi_dsi_device(dev);
- else
return 0;
I think this check is redundant. I'm not aware of any case where the bus ->match() callback is called on a device that isn't on said bus.
- /* attempt OF style match */
- if (of_driver_match_device(dev, drv))
return 1;
- /* compare dsi device and driver names */
"DSI", please.
- if (!strcmp(dsi->name, drv->name))
return 1;
- return 0;
}
static const struct dev_pm_ops mipi_dsi_device_pm_ops = { @@ -125,6 +142,7 @@ struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, dsi->dev.type = &mipi_dsi_device_type; dsi->dev.of_node = info->node; dsi->channel = info->reg;
- strlcpy(dsi->name, info->type, sizeof(dsi->name));
Don't you need to check info->type != NULL before doing this?
dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), info->reg);
@@ -148,6 +166,11 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) int ret; u32 reg;
- if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
dev_err(dev, "modalias failure on %s\n", node->full_name);
return ERR_PTR(-EINVAL);
- }
- ret = of_property_read_u32(node, "reg", ®); if (ret) { dev_err(dev, "device node %s has no valid reg property: %d\n",
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 90f4f3c..cb084af 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -139,8 +139,11 @@ enum mipi_dsi_pixel_format { MIPI_DSI_FMT_RGB565, };
+#define DSI_DEV_NAME_SIZE 20
/**
- struct mipi_dsi_device_info - template for creating a mipi_dsi_device
- @type: dsi peripheral chip type
- @reg: DSI virtual channel assigned to peripheral
- @node: pointer to OF device node
@@ -148,6 +151,7 @@ enum mipi_dsi_pixel_format {
- DSI device
*/ struct mipi_dsi_device_info {
- char type[DSI_DEV_NAME_SIZE];
Why limit ourselves to 20 characters? And why even so complicated? Isn't the type always static when someone specifies this? Couldn't we simply use a const char *name here instead?
Thierry
On 1/21/2016 9:35 PM, Thierry Reding wrote:
On Thu, Dec 10, 2015 at 06:11:37PM +0530, Archit Taneja wrote:
Add a device name field in mipi_dsi_device. This name is different from the actual dev name (which is of the format "hostname.reg"). When the device is created via DT, this name is set to the modalias string.
Why? What's the use of setting this to the modalias string?
There is no use to set it in the DT case. It's just set for the sake of consistency between the non-DT and DT devices. For now, dsi->name is just used for device/driver matching for non-DT devices. There's no harm in setting it to a valid name for DT devices.
In the non-DT case, the driver creating the DSI device provides the name by populating a filed in mipi_dsi_device_info.
Matching for DT case would be as it was before. For the non-DT case, we compare the device and driver names. Other buses (like i2c/spi)
"I2C" and "SPI", please.
perform a non-DT match by comparing the device name and entries in the driver's id_table. Such a mechanism isn't used for the dsi bus.
"DSI", please.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org
drivers/gpu/drm/drm_mipi_dsi.c | 25 ++++++++++++++++++++++++- include/drm/drm_mipi_dsi.h | 6 ++++++ 2 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 9434585..5a46802 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -45,9 +45,26 @@
- subset of the MIPI DCS command set.
*/
+static const struct device_type mipi_dsi_device_type;
- static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv) {
- return of_driver_match_device(dev, drv);
- struct mipi_dsi_device *dsi;
- if (dev->type == &mipi_dsi_device_type)
dsi = to_mipi_dsi_device(dev);
- else
return 0;
I think this check is redundant. I'm not aware of any case where the bus ->match() callback is called on a device that isn't on said bus.
You're right. I'll drop this.
- /* attempt OF style match */
- if (of_driver_match_device(dev, drv))
return 1;
- /* compare dsi device and driver names */
"DSI", please.
if (!strcmp(dsi->name, drv->name))
return 1;
return 0; }
static const struct dev_pm_ops mipi_dsi_device_pm_ops = {
@@ -125,6 +142,7 @@ struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, dsi->dev.type = &mipi_dsi_device_type; dsi->dev.of_node = info->node; dsi->channel = info->reg;
- strlcpy(dsi->name, info->type, sizeof(dsi->name));
Don't you need to check info->type != NULL before doing this?
It's not needed with the way struct mipi_dsi_device_info is currently defined.
dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), info->reg);
@@ -148,6 +166,11 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) int ret; u32 reg;
- if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
dev_err(dev, "modalias failure on %s\n", node->full_name);
return ERR_PTR(-EINVAL);
- }
- ret = of_property_read_u32(node, "reg", ®); if (ret) { dev_err(dev, "device node %s has no valid reg property: %d\n",
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 90f4f3c..cb084af 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -139,8 +139,11 @@ enum mipi_dsi_pixel_format { MIPI_DSI_FMT_RGB565, };
+#define DSI_DEV_NAME_SIZE 20
- /**
- struct mipi_dsi_device_info - template for creating a mipi_dsi_device
- @type: dsi peripheral chip type
- @reg: DSI virtual channel assigned to peripheral
- @node: pointer to OF device node
@@ -148,6 +151,7 @@ enum mipi_dsi_pixel_format {
- DSI device
*/ struct mipi_dsi_device_info {
- char type[DSI_DEV_NAME_SIZE];
Why limit ourselves to 20 characters? And why even so complicated? Isn't the type always static when someone specifies this? Couldn't we simply use a const char *name here instead?
In the case where the device is registered via DT, we would need space allocated for 'type' to copy the modalias string into it. Having const char *type would make it a bit complicated for the DT path.
The mipi_dsi_device_info struct was based on the i2c_board_info/spi_board_info structs, and they have type/modalias members declared as array of chars. I kind of followed suit without putting to much thought on member type.
Archit
Thierry
We don't check whether a previously registered mipi_dsi_device under the same host shares the same virtual channel.
Before registering, check if any of the registered devices doesn't already have the same virtual channel.
This wasn't crucial when all the devices under a host were populated via DT. Now that we also support creating devices manually, we could end up in a situation where a driver tries to create a device with a virtual channel already taken by a device populated in DT.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 5a46802..7a81171 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -119,6 +119,22 @@ static const struct device_type mipi_dsi_device_type = { .release = mipi_dsi_dev_release, };
+static int __dsi_check_chan_busy(struct device *dev, void *data) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); + u32 *reg = data; + + if (dsi && dsi->channel == *reg) + return -EBUSY; + + return 0; +} + +static int mipi_dsi_check_chan_busy(struct mipi_dsi_host *host, u32 reg) +{ + return device_for_each_child(host->dev, ®, __dsi_check_chan_busy); +} + struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, struct mipi_dsi_device_info *info) { @@ -146,14 +162,20 @@ struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host,
dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), info->reg);
+ ret = mipi_dsi_check_chan_busy(host, info->reg); + if (ret) + goto err; + ret = device_register(&dsi->dev); if (ret) { dev_err(dev, "failed to register device: %d\n", ret); - kfree(dsi); - return ERR_PTR(ret); + goto err; }
return dsi; +err: + kfree(dsi); + return ERR_PTR(ret); } EXPORT_SYMBOL(mipi_dsi_device_new);
On Thu, Dec 10, 2015 at 06:11:38PM +0530, Archit Taneja wrote:
We don't check whether a previously registered mipi_dsi_device under the same host shares the same virtual channel.
Before registering, check if any of the registered devices doesn't already have the same virtual channel.
This wasn't crucial when all the devices under a host were populated via DT. Now that we also support creating devices manually, we could end up in a situation where a driver tries to create a device with a virtual channel already taken by a device populated in DT.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org
drivers/gpu/drm/drm_mipi_dsi.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
I don't think this is necessary. The device name will be composed of the host's name, a '.' and the virtual channel ID, and the device core will refuse to create two devices with the same name.
Thierry
On 01/21/2016 09:41 PM, Thierry Reding wrote:
On Thu, Dec 10, 2015 at 06:11:38PM +0530, Archit Taneja wrote:
We don't check whether a previously registered mipi_dsi_device under the same host shares the same virtual channel.
Before registering, check if any of the registered devices doesn't already have the same virtual channel.
This wasn't crucial when all the devices under a host were populated via DT. Now that we also support creating devices manually, we could end up in a situation where a driver tries to create a device with a virtual channel already taken by a device populated in DT.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org
drivers/gpu/drm/drm_mipi_dsi.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
I don't think this is necessary. The device name will be composed of the host's name, a '.' and the virtual channel ID, and the device core will refuse to create two devices with the same name.
That's a good point. I'll drop this patch.
Archit
Thierry
A driver calling mipi_dsi_device_new might want to unregister the device once it's done. It might also require it in an error handling path in case something didn't go right.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org --- include/drm/drm_mipi_dsi.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index cb084af..410d8b5 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -195,6 +195,11 @@ ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,
struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, struct mipi_dsi_device_info *info); +static inline void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi) +{ + device_unregister(&dsi->dev); +} + /** * enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode * @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking
On Thu, Dec 10, 2015 at 06:11:39PM +0530, Archit Taneja wrote:
A driver calling mipi_dsi_device_new might want to unregister the device once it's done. It might also require it in an error handling path in case something didn't go right.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org
include/drm/drm_mipi_dsi.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index cb084af..410d8b5 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -195,6 +195,11 @@ ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,
struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, struct mipi_dsi_device_info *info); +static inline void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi) +{
- device_unregister(&dsi->dev);
+}
This is the same, essentially, as mipi_dsi_remove_device_fn(). I think this should move into drm_mipi_dsi.c and mipi_dsi_remove_device_fn() should call this new function so that both OF and !OF share the same code for this.
Thierry
On 01/21/2016 09:42 PM, Thierry Reding wrote:
On Thu, Dec 10, 2015 at 06:11:39PM +0530, Archit Taneja wrote:
A driver calling mipi_dsi_device_new might want to unregister the device once it's done. It might also require it in an error handling path in case something didn't go right.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org
include/drm/drm_mipi_dsi.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index cb084af..410d8b5 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -195,6 +195,11 @@ ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,
struct mipi_dsi_device *mipi_dsi_device_new(struct mipi_dsi_host *host, struct mipi_dsi_device_info *info); +static inline void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi) +{
- device_unregister(&dsi->dev);
+}
This is the same, essentially, as mipi_dsi_remove_device_fn(). I think this should move into drm_mipi_dsi.c and mipi_dsi_remove_device_fn() should call this new function so that both OF and !OF share the same code for this.
I can do this.
Thanks, Archit
mipi_dsi_devices are inherently aware of their host because they share a parent-child hierarchy in the device tree.
non-dsi drivers that create dsi device don't have this data. In order to get this information, they require to a phandle to the dsi host in the device tree.
Maintain a list of all the hosts DSI that are currently registered.
This list will be used to find the mipi_dsi_host corresponding to the device_node passed in of_find_mipi_dsi_host_by_node.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 38 ++++++++++++++++++++++++++++++++++++++ include/drm/drm_mipi_dsi.h | 3 +++ 2 files changed, 41 insertions(+)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 7a81171..e40a665 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -213,6 +213,36 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) } #endif
+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 + * @node: device tree node + * + * Return: A pointer to the MIPI DSI host corresponding to @np or NULL if no + * such device exists (or has not been registered yet). + */ +struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node) +{ + struct mipi_dsi_host *host; + + mutex_lock(&host_lock); + + list_for_each_entry(host, &host_list, list) { + if (host->dev->of_node == node) { + mutex_unlock(&host_lock); + return host; + } + } + + mutex_unlock(&host_lock); + + return NULL; +} +EXPORT_SYMBOL(of_find_mipi_dsi_host_by_node); + int mipi_dsi_host_register(struct mipi_dsi_host *host) { struct device_node *node; @@ -224,6 +254,10 @@ int mipi_dsi_host_register(struct mipi_dsi_host *host) of_mipi_dsi_device_add(host, node); }
+ mutex_lock(&host_lock); + list_add_tail(&host->list, &host_list); + mutex_unlock(&host_lock); + return 0; } EXPORT_SYMBOL(mipi_dsi_host_register); @@ -240,6 +274,10 @@ static int mipi_dsi_remove_device_fn(struct device *dev, void *priv) void mipi_dsi_host_unregister(struct mipi_dsi_host *host) { device_for_each_child(host->dev, NULL, mipi_dsi_remove_device_fn); + + mutex_lock(&host_lock); + list_del_init(&host->list); + mutex_unlock(&host_lock); } EXPORT_SYMBOL(mipi_dsi_host_unregister);
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 410d8b5..e5c1df9 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -96,14 +96,17 @@ struct mipi_dsi_host_ops { * struct mipi_dsi_host - DSI host device * @dev: driver model device node for this DSI host * @ops: DSI host operations + * @list: list management */ struct mipi_dsi_host { struct device *dev; const struct mipi_dsi_host_ops *ops; + struct list_head list; };
int mipi_dsi_host_register(struct mipi_dsi_host *host); void mipi_dsi_host_unregister(struct mipi_dsi_host *host); +struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node);
/* DSI mode flags */
On Thu, Dec 10, 2015 at 06:11:40PM +0530, Archit Taneja wrote:
mipi_dsi_devices are inherently aware of their host because they share a parent-child hierarchy in the device tree.
non-dsi drivers that create dsi device don't have this data. In order to get this information, they require to a phandle to the dsi host in the device tree.
Maintain a list of all the hosts DSI that are currently registered.
This list will be used to find the mipi_dsi_host corresponding to the device_node passed in of_find_mipi_dsi_host_by_node.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org
drivers/gpu/drm/drm_mipi_dsi.c | 38 ++++++++++++++++++++++++++++++++++++++ include/drm/drm_mipi_dsi.h | 3 +++ 2 files changed, 41 insertions(+)
Please be more consistent with the spelling. Abbreviations should be all capitals. Also s/mipi_dsi_devices/MIPI DSI devices/, and so on.
Otherwise I guess this makes sense.
Thierry
On 01/21/2016 09:46 PM, Thierry Reding wrote:
On Thu, Dec 10, 2015 at 06:11:40PM +0530, Archit Taneja wrote:
mipi_dsi_devices are inherently aware of their host because they share a parent-child hierarchy in the device tree.
non-dsi drivers that create dsi device don't have this data. In order to get this information, they require to a phandle to the dsi host in the device tree.
Maintain a list of all the hosts DSI that are currently registered.
This list will be used to find the mipi_dsi_host corresponding to the device_node passed in of_find_mipi_dsi_host_by_node.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org
drivers/gpu/drm/drm_mipi_dsi.c | 38 ++++++++++++++++++++++++++++++++++++++ include/drm/drm_mipi_dsi.h | 3 +++ 2 files changed, 41 insertions(+)
Please be more consistent with the spelling. Abbreviations should be all capitals. Also s/mipi_dsi_devices/MIPI DSI devices/, and so on.
I'll ensure the abbreviations are consistent in the next revision.
Otherwise I guess this makes sense.
Thanks for the review.
Thanks, Archit
Hi Thierry,
Can you pick up these DSI patches, or would it make more sense for these to go via someone else?
Thanks, Archit
On 12/10/2015 06:11 PM, Archit Taneja wrote:
We are currently restricted when it comes to supporting DSI on devices that have a non-DSI control bus. For example, DSI encoder chips are available in the market that are configured via i2c. Configuring their registers via DSI bus is either optional or not available at all.
These devices still need to pass DSI parameters (data lanes, mode flags etc) to the DSI host they are connected to. We don't have a way to do that at the moment.
After some discussions on the previous RFC[1], we decided to support this by providing additional API in drm_mipi_dsi which lets us create new DSI devices without the need of them to have a DT node.
Changes in v4:
- Added a new patch that fixes build issues when CONFIG_OF is not set.
Changes in v3:
- Incorporated misc comments by Andrzej. Changed from RFC to a PATCH set.
- Fixed htmldocs warnings.
Archit Taneja (6): drm/dsi: check for CONFIG_OF when defining of_mipi_dsi_device_add drm/dsi: Refactor device creation drm/dsi: Try to match non-DT dsi devices drm/dsi: Check for used channels drm/dsi: Add routine to unregister dsi device drm/dsi: Get DSI host by DT device node
drivers/gpu/drm/drm_mipi_dsi.c | 144 ++++++++++++++++++++++++++++++++--------- include/drm/drm_mipi_dsi.h | 29 +++++++++ 2 files changed, 141 insertions(+), 32 deletions(-)
We are currently restricted when it comes to supporting DSI on devices that have a non-DSI control bus. For example, DSI encoder chips are available in the market that are configured via i2c. Configuring their registers via DSI bus is either optional or not available at all.
These devices still need to pass DSI parameters (data lanes, mode flags etc) to the DSI host they are connected to. We don't have a way to do that at the moment.
After some discussions on the previous RFC[1], we decided to support this by providing additional API in drm_mipi_dsi.c which lets us create new DSI devices without the need of them to have a DT node.
[1]: https://lkml.org/lkml/2015/6/30/42
Changes in v5: - Simplify refactoring as suggested by Thierry. - Use abbreviations correctly. - Drop "drm/dsi: Check for used channels" - Return the correct encoded error code for of_mipi_dsi_device_add when CONFIG_OF is disabled. - Use mipi_dsi_device_unregister to implement mipi_dsi_remove_device_fn() too.
Changes in v4: - Added a new patch that fixes build issues when CONFIG_OF is not set.
Changes in v3:
- Incorporated misc comments by Andrzej. Changed from RFC to a PATCH set. - Fixed htmldocs warnings.
Archit Taneja (5): drm/dsi: check for CONFIG_OF when defining of_mipi_dsi_device_add drm/dsi: Use mipi_dsi_device_register_full for DSI device creation drm/dsi: Try to match non-DT DSI devices drm/dsi: Add routine to unregister a DSI device drm/dsi: Get DSI host by DT device node
drivers/gpu/drm/drm_mipi_dsi.c | 127 +++++++++++++++++++++++++++++++++++++---- include/drm/drm_mipi_dsi.h | 26 +++++++++ 2 files changed, 141 insertions(+), 12 deletions(-)
of_mipi_dsi_device_add is used only when CONFIG_OF is enabled. It currently works if OF support is disabled, but this will change when we add more functionality to it.
Define the original func if CONFIG_OF is enabled. Define a dummy func otherwise.
Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 6e6a9c5..4f2a704 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -129,6 +129,7 @@ static int mipi_dsi_device_add(struct mipi_dsi_device *dsi) return device_add(&dsi->dev); }
+#if IS_ENABLED(CONFIG_OF) static struct mipi_dsi_device * of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) { @@ -170,6 +171,13 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node)
return dsi; } +#else +static struct mipi_dsi_device * +of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) +{ + return ERR_PTR(-ENODEV); +} +#endif
int mipi_dsi_host_register(struct mipi_dsi_host *host) {
Use mipi_dsi_device_register_full for device creation. This takes in mipi_dsi_device_info as a template to populate the DSI device information.
The reason to introduce this is to have a way to create DSI devices not available via DT. Drivers that want to create a DSI device can populate mipi_dsi_device_info and call this function. For DSI devices available via DT, of_mipi_dsi_device_add is used as before, but this now calls mipi_dsi_device_register_full internally.
Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 64 +++++++++++++++++++++++++++++++----------- include/drm/drm_mipi_dsi.h | 16 +++++++++++ 2 files changed, 63 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 4f2a704..5d7243d 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -133,8 +133,8 @@ static int mipi_dsi_device_add(struct mipi_dsi_device *dsi) static struct mipi_dsi_device * of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) { - struct mipi_dsi_device *dsi; struct device *dev = host->dev; + struct mipi_dsi_device_info info = { }; int ret; u32 reg;
@@ -145,39 +145,69 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) return ERR_PTR(-EINVAL); }
- if (reg > 3) { - dev_err(dev, "device node %s has invalid reg property: %u\n", - node->full_name, reg); + info.channel = reg; + info.node = of_node_get(node); + + return mipi_dsi_device_register_full(host, &info); +} +#else +static struct mipi_dsi_device * +of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) +{ + return ERR_PTR(-ENODEV); +} +#endif + +/** + * mipi_dsi_device_register_full - create a MIPI DSI device + * @host: DSI host to which this device is connected + * @info: pointer to template containing DSI device information + * + * Create a MIPI DSI device by using the device information provided by + * mipi_dsi_device_info template + * + * Returns: + * A pointer to the newly created MIPI DSI device, or, a pointer encoded + * with an error + */ +struct mipi_dsi_device * +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; + int ret; + + if (!info) { + dev_err(dev, "invalid mipi_dsi_device_info pointer\n"); + return ERR_PTR(-EINVAL); + } + + if (info->channel > 3) { + dev_err(dev, "invalid virtual channel: %u\n", info->channel); return ERR_PTR(-EINVAL); }
dsi = mipi_dsi_device_alloc(host); if (IS_ERR(dsi)) { - dev_err(dev, "failed to allocate DSI device %s: %ld\n", - node->full_name, PTR_ERR(dsi)); + dev_err(dev, "failed to allocate DSI device %ld\n", + PTR_ERR(dsi)); return dsi; }
- dsi->dev.of_node = of_node_get(node); - dsi->channel = reg; + dsi->dev.of_node = info->node; + dsi->channel = info->channel;
ret = mipi_dsi_device_add(dsi); if (ret) { - dev_err(dev, "failed to add DSI device %s: %d\n", - node->full_name, ret); + dev_err(dev, "failed to add DSI device %d\n", ret); kfree(dsi); return ERR_PTR(ret); }
return dsi; } -#else -static struct mipi_dsi_device * -of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) -{ - return ERR_PTR(-ENODEV); -} -#endif +EXPORT_SYMBOL(mipi_dsi_device_register_full);
int mipi_dsi_host_register(struct mipi_dsi_host *host) { diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 1b3b1f8..ce5eae43 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -139,6 +139,19 @@ enum mipi_dsi_pixel_format { MIPI_DSI_FMT_RGB565, };
+ /** + * struct mipi_dsi_device_info - template for creating a mipi_dsi_device + * @channel: DSI virtual channel assigned to peripheral + * @node: pointer to OF device node + * + * This is populated and passed to mipi_dsi_device_new to create a new + * DSI device + */ +struct mipi_dsi_device_info { + u32 channel; + struct device_node *node; +}; + /** * struct mipi_dsi_device - DSI peripheral device * @host: DSI host for this peripheral @@ -188,6 +201,9 @@ static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt) return -EINVAL; }
+struct mipi_dsi_device * +mipi_dsi_device_register_full(struct mipi_dsi_host *host, + const struct mipi_dsi_device_info *info); struct mipi_dsi_device *of_find_mipi_dsi_device_by_node(struct device_node *np); int mipi_dsi_attach(struct mipi_dsi_device *dsi); int mipi_dsi_detach(struct mipi_dsi_device *dsi);
Add a device name field in mipi_dsi_device. This name is different from the actual dev name (which is of the format "hostname.reg"). When the device is created via DT, this name is set to the modalias string. In the non-DT case, the driver creating the DSI device provides the name by populating a filed in mipi_dsi_device_info.
Matching for DT case would be as it was before. For the non-DT case, we compare the device and driver names. Other buses (like I2C/SPI) perform a non-DT match by comparing the device name and entries in the driver's id_table. Such a mechanism isn't used for the DSI bus.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 18 +++++++++++++++++- include/drm/drm_mipi_dsi.h | 10 ++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 5d7243d..42a7aac 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -47,7 +47,17 @@
static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv) { - return of_driver_match_device(dev, drv); + struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); + + /* attempt OF style match */ + if (of_driver_match_device(dev, drv)) + return 1; + + /* compare DSI device and driver names */ + if (!strcmp(dsi->name, drv->name)) + return 1; + + return 0; }
static const struct dev_pm_ops mipi_dsi_device_pm_ops = { @@ -138,6 +148,11 @@ of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) int ret; u32 reg;
+ if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { + dev_err(dev, "modalias failure on %s\n", node->full_name); + return ERR_PTR(-EINVAL); + } + ret = of_property_read_u32(node, "reg", ®); if (ret) { dev_err(dev, "device node %s has no valid reg property: %d\n", @@ -197,6 +212,7 @@ mipi_dsi_device_register_full(struct mipi_dsi_host *host,
dsi->dev.of_node = info->node; dsi->channel = info->channel; + strlcpy(dsi->name, info->type, sizeof(dsi->name));
ret = mipi_dsi_device_add(dsi); if (ret) { diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index ce5eae43..a914116 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -139,15 +139,19 @@ enum mipi_dsi_pixel_format { MIPI_DSI_FMT_RGB565, };
- /** +#define DSI_DEV_NAME_SIZE 20 + +/** * struct mipi_dsi_device_info - template for creating a mipi_dsi_device + * @type: DSI peripheral chip type * @channel: DSI virtual channel assigned to peripheral - * @node: pointer to OF device node + * @node: pointer to OF device node or NULL * * This is populated and passed to mipi_dsi_device_new to create a new * DSI device */ struct mipi_dsi_device_info { + char type[DSI_DEV_NAME_SIZE]; u32 channel; struct device_node *node; }; @@ -156,6 +160,7 @@ struct mipi_dsi_device_info { * struct mipi_dsi_device - DSI peripheral device * @host: DSI host for this peripheral * @dev: driver model device node for this peripheral + * @name: DSI peripheral chip type * @channel: virtual channel assigned to the peripheral * @format: pixel format for video mode * @lanes: number of active data lanes @@ -165,6 +170,7 @@ struct mipi_dsi_device { struct mipi_dsi_host *host; struct device dev;
+ char name[DSI_DEV_NAME_SIZE]; unsigned int channel; unsigned int lanes; enum mipi_dsi_pixel_format format;
A driver calling mipi_dsi_device_register_full might want to unregister the device once it's done. It might also require it in an error handling path in case something didn't go right.
Create mipi_dsi_device_unregister for this purpse, use it within mipi_dsi_remove_device_fn as it does the same thing.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 12 +++++++++++- include/drm/drm_mipi_dsi.h | 1 + 2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 42a7aac..f2f5a6d 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -225,6 +225,16 @@ mipi_dsi_device_register_full(struct mipi_dsi_host *host, } EXPORT_SYMBOL(mipi_dsi_device_register_full);
+/** + * mipi_dsi_device_unregister - unregister MIPI DSI device + * @dsi: DSI peripheral device + */ +void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi) +{ + device_unregister(&dsi->dev); +} +EXPORT_SYMBOL(mipi_dsi_device_unregister); + int mipi_dsi_host_register(struct mipi_dsi_host *host) { struct device_node *node; @@ -244,7 +254,7 @@ static int mipi_dsi_remove_device_fn(struct device *dev, void *priv) { struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
- device_unregister(&dsi->dev); + mipi_dsi_device_unregister(dsi);
return 0; } diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index a914116..06e0a93 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -210,6 +210,7 @@ static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt) struct mipi_dsi_device * mipi_dsi_device_register_full(struct mipi_dsi_host *host, const struct mipi_dsi_device_info *info); +void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi); struct mipi_dsi_device *of_find_mipi_dsi_device_by_node(struct device_node *np); int mipi_dsi_attach(struct mipi_dsi_device *dsi); int mipi_dsi_detach(struct mipi_dsi_device *dsi);
MIPI DSI devices are inherently aware of their host because they share a parent-child hierarchy in the device tree.
Non-DSI drivers that create DSI device don't have this data. In order to get this information, they require to a phandle to the DSI host in the device tree.
Maintain a list of all the hosts DSI that are currently registered. This list will be used to find the mipi_dsi_host corresponding to the device_node passed in of_find_mipi_dsi_host_by_node.
Reviewed-by: Andrzej Hajda a.hajda@samsung.com Signed-off-by: Archit Taneja architt@codeaurora.org --- drivers/gpu/drm/drm_mipi_dsi.c | 39 +++++++++++++++++++++++++++++++++++++++ include/drm/drm_mipi_dsi.h | 3 +++ 2 files changed, 42 insertions(+)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index f2f5a6d..f5d8083 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -235,6 +235,37 @@ 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 + * @node: device tree node + * + * Returns: + * A pointer to the MIPI DSI host corresponding to @node or NULL if no + * such device exists (or has not been registered yet). + */ +struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node) +{ + struct mipi_dsi_host *host; + + mutex_lock(&host_lock); + + list_for_each_entry(host, &host_list, list) { + if (host->dev->of_node == node) { + mutex_unlock(&host_lock); + return host; + } + } + + mutex_unlock(&host_lock); + + return NULL; +} +EXPORT_SYMBOL(of_find_mipi_dsi_host_by_node); + int mipi_dsi_host_register(struct mipi_dsi_host *host) { struct device_node *node; @@ -246,6 +277,10 @@ int mipi_dsi_host_register(struct mipi_dsi_host *host) of_mipi_dsi_device_add(host, node); }
+ mutex_lock(&host_lock); + list_add_tail(&host->list, &host_list); + mutex_unlock(&host_lock); + return 0; } EXPORT_SYMBOL(mipi_dsi_host_register); @@ -262,6 +297,10 @@ static int mipi_dsi_remove_device_fn(struct device *dev, void *priv) void mipi_dsi_host_unregister(struct mipi_dsi_host *host) { device_for_each_child(host->dev, NULL, mipi_dsi_remove_device_fn); + + mutex_lock(&host_lock); + list_del_init(&host->list); + mutex_unlock(&host_lock); } EXPORT_SYMBOL(mipi_dsi_host_unregister);
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 06e0a93..7a9840f 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -96,14 +96,17 @@ struct mipi_dsi_host_ops { * struct mipi_dsi_host - DSI host device * @dev: driver model device node for this DSI host * @ops: DSI host operations + * @list: list management */ struct mipi_dsi_host { struct device *dev; const struct mipi_dsi_host_ops *ops; + struct list_head list; };
int mipi_dsi_host_register(struct mipi_dsi_host *host); void mipi_dsi_host_unregister(struct mipi_dsi_host *host); +struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node);
/* DSI mode flags */
On Fri, Feb 12, 2016 at 02:48:29PM +0530, Archit Taneja wrote:
We are currently restricted when it comes to supporting DSI on devices that have a non-DSI control bus. For example, DSI encoder chips are available in the market that are configured via i2c. Configuring their registers via DSI bus is either optional or not available at all.
These devices still need to pass DSI parameters (data lanes, mode flags etc) to the DSI host they are connected to. We don't have a way to do that at the moment.
After some discussions on the previous RFC[1], we decided to support this by providing additional API in drm_mipi_dsi.c which lets us create new DSI devices without the need of them to have a DT node.
Changes in v5:
- Simplify refactoring as suggested by Thierry.
- Use abbreviations correctly.
- Drop "drm/dsi: Check for used channels"
- Return the correct encoded error code for of_mipi_dsi_device_add when CONFIG_OF is disabled.
- Use mipi_dsi_device_unregister to implement mipi_dsi_remove_device_fn() too.
Changes in v4:
- Added a new patch that fixes build issues when CONFIG_OF is not set.
Changes in v3:
- Incorporated misc comments by Andrzej. Changed from RFC to a PATCH set.
- Fixed htmldocs warnings.
Archit Taneja (5): drm/dsi: check for CONFIG_OF when defining of_mipi_dsi_device_add drm/dsi: Use mipi_dsi_device_register_full for DSI device creation drm/dsi: Try to match non-DT DSI devices drm/dsi: Add routine to unregister a DSI device drm/dsi: Get DSI host by DT device node
drivers/gpu/drm/drm_mipi_dsi.c | 127 +++++++++++++++++++++++++++++++++++++---- include/drm/drm_mipi_dsi.h | 26 +++++++++ 2 files changed, 141 insertions(+), 12 deletions(-)
I've applied this with minor fixups and cleanups to the commit messages.
Thanks, Thierry
dri-devel@lists.freedesktop.org