From c63ae8a9686bb8c87154a31dc5ebadbda778a8e5 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 12 Feb 2016 14:48:31 +0530 Subject: drm/dsi: Use mipi_dsi_device_register_full() for DSI device creation Use mipi_dsi_device_register_full() for device creation. This takes in a struct 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 a struct 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 Signed-off-by: Thierry Reding --- include/drm/drm_mipi_dsi.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'include') diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 1b3b1f8c8cdf..ce5eae438fd1 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); -- cgit v1.2.3 From bf4363ce3a67ba06042351f40841ef4da9b30787 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 12 Feb 2016 14:48:32 +0530 Subject: drm/dsi: Try to match non-DT DSI devices Add a device name field in struct mipi_dsi_device. This name is not the same as the device 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 field in struct 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 Signed-off-by: Archit Taneja Signed-off-by: Thierry Reding --- drivers/gpu/drm/drm_mipi_dsi.c | 18 +++++++++++++++++- include/drm/drm_mipi_dsi.h | 10 ++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 5d7243da2323..42a7aacf7a2f 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 ce5eae438fd1..a91411682e83 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; -- cgit v1.2.3 From 509e42ce0441df39d5241150c1bec32cf6347b6c Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 12 Feb 2016 14:48:33 +0530 Subject: drm/dsi: Add routine to unregister a DSI device A driver calling mipi_dsi_device_register_full() might want to remove the device once it's done. It might also require it in an error handling path in case something went wrong. Create mipi_dsi_device_unregister() for this purpose and use it within mipi_dsi_remove_device_fn() as it does the same thing. Reviewed-by: Andrzej Hajda Signed-off-by: Archit Taneja Signed-off-by: Thierry Reding --- drivers/gpu/drm/drm_mipi_dsi.c | 12 +++++++++++- include/drm/drm_mipi_dsi.h | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 42a7aacf7a2f..f2f5a6d3669a 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 a91411682e83..06e0a9382b35 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); -- cgit v1.2.3 From 97b6ae50e05c533b6455e304d36bdf2bb5604ee6 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 12 Feb 2016 14:48:34 +0530 Subject: drm/dsi: Get DSI host by DT device node 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 DSI hosts that are currently registered. This list will be used to find the struct mipi_dsi_host corresponding to the device tree node passed to of_find_mipi_dsi_host_by_node(). Reviewed-by: Andrzej Hajda Signed-off-by: Archit Taneja Signed-off-by: Thierry Reding --- drivers/gpu/drm/drm_mipi_dsi.c | 39 +++++++++++++++++++++++++++++++++++++++ include/drm/drm_mipi_dsi.h | 3 +++ 2 files changed, 42 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index f2f5a6d3669a..f5d80839a90c 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 06e0a9382b35..7a9840f8b38e 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 */ -- cgit v1.2.3 From c8a3b2ae07130042682bc8e031bcfbae3754463d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 26 Feb 2016 11:51:06 +0200 Subject: drm/bridge: Make (pre/post) enable/disable callbacks optional Instead of forcing bridges to implement empty callbacks make them all optional. Signed-off-by: Laurent Pinchart Signed-off-by: Thierry Reding --- drivers/gpu/drm/drm_bridge.c | 12 ++++++++---- include/drm/drm_crtc.h | 8 ++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index bd93453afa61..b3654404abd0 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -186,7 +186,8 @@ void drm_bridge_disable(struct drm_bridge *bridge) drm_bridge_disable(bridge->next); - bridge->funcs->disable(bridge); + if (bridge->funcs->disable) + bridge->funcs->disable(bridge); } EXPORT_SYMBOL(drm_bridge_disable); @@ -206,7 +207,8 @@ void drm_bridge_post_disable(struct drm_bridge *bridge) if (!bridge) return; - bridge->funcs->post_disable(bridge); + if (bridge->funcs->post_disable) + bridge->funcs->post_disable(bridge); drm_bridge_post_disable(bridge->next); } @@ -256,7 +258,8 @@ void drm_bridge_pre_enable(struct drm_bridge *bridge) drm_bridge_pre_enable(bridge->next); - bridge->funcs->pre_enable(bridge); + if (bridge->funcs->pre_enable) + bridge->funcs->pre_enable(bridge); } EXPORT_SYMBOL(drm_bridge_pre_enable); @@ -276,7 +279,8 @@ void drm_bridge_enable(struct drm_bridge *bridge) if (!bridge) return; - bridge->funcs->enable(bridge); + if (bridge->funcs->enable) + bridge->funcs->enable(bridge); drm_bridge_enable(bridge->next); } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index c65a212db77e..f336671ca932 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1581,6 +1581,8 @@ struct drm_bridge_funcs { * * The bridge can assume that the display pipe (i.e. clocks and timing * signals) feeding it is still running when this callback is called. + * + * The disable callback is optional. */ void (*disable)(struct drm_bridge *bridge); @@ -1597,6 +1599,8 @@ struct drm_bridge_funcs { * The bridge must assume that the display pipe (i.e. clocks and timing * singals) feeding it is no longer running when this callback is * called. + * + * The post_disable callback is optional. */ void (*post_disable)(struct drm_bridge *bridge); @@ -1625,6 +1629,8 @@ struct drm_bridge_funcs { * will not yet be running when this callback is called. The bridge must * not enable the display link feeding the next bridge in the chain (if * there is one) when this callback is called. + * + * The pre_enable callback is optional. */ void (*pre_enable)(struct drm_bridge *bridge); @@ -1642,6 +1648,8 @@ struct drm_bridge_funcs { * signals) feeding it is running when this callback is called. This * callback must enable the display link feeding the next bridge in the * chain if there is one. + * + * The enable callback is optional. */ void (*enable)(struct drm_bridge *bridge); }; -- cgit v1.2.3