diff options
Diffstat (limited to 'drivers/gpu/drm/omapdrm/dss/base.c')
| -rw-r--r-- | drivers/gpu/drm/omapdrm/dss/base.c | 217 |
1 files changed, 179 insertions, 38 deletions
diff --git a/drivers/gpu/drm/omapdrm/dss/base.c b/drivers/gpu/drm/omapdrm/dss/base.c index 13e91faaf7a6..a4ac113e1690 100644 --- a/drivers/gpu/drm/omapdrm/dss/base.c +++ b/drivers/gpu/drm/omapdrm/dss/base.c @@ -1,44 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * OMAP Display Subsystem Base + * + * Copyright (C) 2015-2017 Texas Instruments Incorporated - https://www.ti.com/ + */ + #include <linux/kernel.h> +#include <linux/list.h> #include <linux/module.h> +#include <linux/mutex.h> #include <linux/of.h> #include <linux/of_graph.h> -#include <linux/list.h> +#include <linux/platform_device.h> + +#include "dss.h" #include "omapdss.h" -static bool dss_initialized; -static const struct dispc_ops *ops; +struct dispc_device *dispc_get_dispc(struct dss_device *dss) +{ + return dss->dispc; +} -static struct list_head omapdss_comp_list; +/* ----------------------------------------------------------------------------- + * OMAP DSS Devices Handling + */ -struct omapdss_comp_node { - struct list_head list; - struct device_node *node; - bool dss_core_component; -}; +static LIST_HEAD(omapdss_devices_list); +static DEFINE_MUTEX(omapdss_devices_lock); + +void omapdss_device_register(struct omap_dss_device *dssdev) +{ + mutex_lock(&omapdss_devices_lock); + list_add_tail(&dssdev->list, &omapdss_devices_list); + mutex_unlock(&omapdss_devices_lock); +} + +void omapdss_device_unregister(struct omap_dss_device *dssdev) +{ + mutex_lock(&omapdss_devices_lock); + list_del(&dssdev->list); + mutex_unlock(&omapdss_devices_lock); +} + +static bool omapdss_device_is_registered(struct device_node *node) +{ + struct omap_dss_device *dssdev; + bool found = false; + + mutex_lock(&omapdss_devices_lock); + + list_for_each_entry(dssdev, &omapdss_devices_list, list) { + if (dssdev->dev->of_node == node) { + found = true; + break; + } + } + + mutex_unlock(&omapdss_devices_lock); + return found; +} + +struct omap_dss_device *omapdss_device_get(struct omap_dss_device *dssdev) +{ + if (get_device(dssdev->dev) == NULL) + return NULL; + + return dssdev; +} + +void omapdss_device_put(struct omap_dss_device *dssdev) +{ + put_device(dssdev->dev); +} + +struct omap_dss_device *omapdss_find_device_by_node(struct device_node *node) +{ + struct omap_dss_device *dssdev; + + list_for_each_entry(dssdev, &omapdss_devices_list, list) { + if (dssdev->dev->of_node == node) + return omapdss_device_get(dssdev); + } + + return NULL; +} -void omapdss_set_is_initialized(bool set) +/* + * Search for the next output device starting at @from. Release the reference to + * the @from device, and acquire a reference to the returned device if found. + */ +struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from) { - dss_initialized = set; + struct omap_dss_device *dssdev; + struct list_head *list; + + mutex_lock(&omapdss_devices_lock); + + if (list_empty(&omapdss_devices_list)) { + dssdev = NULL; + goto done; + } + + /* + * Start from the from entry if given or from omapdss_devices_list + * otherwise. + */ + list = from ? &from->list : &omapdss_devices_list; + + list_for_each_entry(dssdev, list, list) { + /* + * Stop if we reach the omapdss_devices_list, that's the end of + * the list. + */ + if (&dssdev->list == &omapdss_devices_list) { + dssdev = NULL; + goto done; + } + + if (dssdev->id && dssdev->bridge) + goto done; + } + + dssdev = NULL; + +done: + if (from) + omapdss_device_put(from); + if (dssdev) + omapdss_device_get(dssdev); + + mutex_unlock(&omapdss_devices_lock); + return dssdev; } -EXPORT_SYMBOL(omapdss_set_is_initialized); -bool omapdss_is_initialized(void) +static bool omapdss_device_is_connected(struct omap_dss_device *dssdev) { - return dss_initialized; + return dssdev->dss; } -EXPORT_SYMBOL(omapdss_is_initialized); -void dispc_set_ops(const struct dispc_ops *o) +int omapdss_device_connect(struct dss_device *dss, + struct omap_dss_device *dst) { - ops = o; + dev_dbg(&dss->pdev->dev, "connect(%s)\n", + dst ? dev_name(dst->dev) : "NULL"); + + if (!dst) + return -EINVAL; + + if (omapdss_device_is_connected(dst)) + return -EBUSY; + + dst->dss = dss; + + return 0; } -EXPORT_SYMBOL(dispc_set_ops); -const struct dispc_ops *dispc_get_ops(void) +void omapdss_device_disconnect(struct dss_device *dss, + struct omap_dss_device *dst) { - return ops; + dev_dbg(&dss->pdev->dev, "disconnect(%s)\n", + dst ? dev_name(dst->dev) : "NULL"); + + if (WARN_ON(!dst)) + return; + + if (!dst->id && !omapdss_device_is_connected(dst)) { + WARN_ON(1); + return; + } + + dst->dss = NULL; } -EXPORT_SYMBOL(dispc_get_ops); + +/* ----------------------------------------------------------------------------- + * Components Handling + */ + +static struct list_head omapdss_comp_list; + +struct omapdss_comp_node { + struct list_head list; + struct device_node *node; + bool dss_core_component; + const char *compat; +}; static bool omapdss_list_contains(const struct device_node *node) { @@ -55,13 +200,20 @@ static bool omapdss_list_contains(const struct device_node *node) static void omapdss_walk_device(struct device *dev, struct device_node *node, bool dss_core) { + struct omapdss_comp_node *comp; struct device_node *n; - struct omapdss_comp_node *comp = devm_kzalloc(dev, sizeof(*comp), - GFP_KERNEL); + const char *compat; + int ret; + + ret = of_property_read_string(node, "compatible", &compat); + if (ret < 0) + return; + comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL); if (comp) { comp->node = node; comp->dss_core_component = dss_core; + comp->compat = compat; list_add(&comp->list, &omapdss_comp_list); } @@ -77,8 +229,7 @@ static void omapdss_walk_device(struct device *dev, struct device_node *node, of_node_put(n); - n = NULL; - while ((n = of_graph_get_next_endpoint(node, n)) != NULL) { + for_each_endpoint_of_node(node, n) { struct device_node *pn = of_graph_get_remote_port_parent(n); if (!pn) @@ -101,22 +252,17 @@ void omapdss_gather_components(struct device *dev) omapdss_walk_device(dev, dev->of_node, true); - for_each_available_child_of_node(dev->of_node, child) { - if (!of_find_property(child, "compatible", NULL)) - continue; - + for_each_available_child_of_node(dev->of_node, child) omapdss_walk_device(dev, child, true); - } } -EXPORT_SYMBOL(omapdss_gather_components); static bool omapdss_component_is_loaded(struct omapdss_comp_node *comp) { if (comp->dss_core_component) return true; - if (omapdss_component_is_display(comp->node)) + if (!strstarts(comp->compat, "omapdss,")) return true; - if (omapdss_component_is_output(comp->node)) + if (omapdss_device_is_registered(comp->node)) return true; return false; @@ -133,8 +279,3 @@ bool omapdss_stack_is_ready(void) return true; } -EXPORT_SYMBOL(omapdss_stack_is_ready); - -MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); -MODULE_DESCRIPTION("OMAP Display Subsystem Base"); -MODULE_LICENSE("GPL v2"); |
