2 * OMAP Display Subsystem Base
4 * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
16 #include <linux/kernel.h>
17 #include <linux/list.h>
18 #include <linux/module.h>
19 #include <linux/mutex.h>
21 #include <linux/of_graph.h>
22 #include <linux/platform_device.h>
27 static struct dss_device *dss_device;
29 struct dss_device *omapdss_get_dss(void)
33 EXPORT_SYMBOL(omapdss_get_dss);
35 void omapdss_set_dss(struct dss_device *dss)
39 EXPORT_SYMBOL(omapdss_set_dss);
41 struct dispc_device *dispc_get_dispc(struct dss_device *dss)
45 EXPORT_SYMBOL(dispc_get_dispc);
47 const struct dispc_ops *dispc_get_ops(struct dss_device *dss)
49 return dss->dispc_ops;
51 EXPORT_SYMBOL(dispc_get_ops);
54 /* -----------------------------------------------------------------------------
55 * OMAP DSS Devices Handling
58 static LIST_HEAD(omapdss_devices_list);
59 static DEFINE_MUTEX(omapdss_devices_lock);
61 void omapdss_device_register(struct omap_dss_device *dssdev)
63 mutex_lock(&omapdss_devices_lock);
64 list_add_tail(&dssdev->list, &omapdss_devices_list);
65 mutex_unlock(&omapdss_devices_lock);
67 EXPORT_SYMBOL_GPL(omapdss_device_register);
69 void omapdss_device_unregister(struct omap_dss_device *dssdev)
71 mutex_lock(&omapdss_devices_lock);
72 list_del(&dssdev->list);
73 mutex_unlock(&omapdss_devices_lock);
75 EXPORT_SYMBOL_GPL(omapdss_device_unregister);
77 static bool omapdss_device_is_registered(struct device_node *node)
79 struct omap_dss_device *dssdev;
82 mutex_lock(&omapdss_devices_lock);
84 list_for_each_entry(dssdev, &omapdss_devices_list, list) {
85 if (dssdev->dev->of_node == node) {
91 mutex_unlock(&omapdss_devices_lock);
95 struct omap_dss_device *omapdss_device_get(struct omap_dss_device *dssdev)
97 if (!try_module_get(dssdev->owner))
100 if (get_device(dssdev->dev) == NULL) {
101 module_put(dssdev->owner);
107 EXPORT_SYMBOL(omapdss_device_get);
109 void omapdss_device_put(struct omap_dss_device *dssdev)
111 put_device(dssdev->dev);
112 module_put(dssdev->owner);
114 EXPORT_SYMBOL(omapdss_device_put);
116 struct omap_dss_device *omapdss_find_device_by_node(struct device_node *node)
118 struct omap_dss_device *dssdev;
120 list_for_each_entry(dssdev, &omapdss_devices_list, list) {
121 if (dssdev->dev->of_node == node)
122 return omapdss_device_get(dssdev);
129 * Search for the next output device starting at @from. Release the reference to
130 * the @from device, and acquire a reference to the returned device if found.
132 struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from)
134 struct omap_dss_device *dssdev;
135 struct list_head *list;
137 mutex_lock(&omapdss_devices_lock);
139 if (list_empty(&omapdss_devices_list)) {
145 * Start from the from entry if given or from omapdss_devices_list
148 list = from ? &from->list : &omapdss_devices_list;
150 list_for_each_entry(dssdev, list, list) {
152 * Stop if we reach the omapdss_devices_list, that's the end of
155 if (&dssdev->list == &omapdss_devices_list) {
160 if (dssdev->id && (dssdev->next || dssdev->bridge))
168 omapdss_device_put(from);
170 omapdss_device_get(dssdev);
172 mutex_unlock(&omapdss_devices_lock);
175 EXPORT_SYMBOL(omapdss_device_next_output);
177 static bool omapdss_device_is_connected(struct omap_dss_device *dssdev)
182 int omapdss_device_connect(struct dss_device *dss,
183 struct omap_dss_device *src,
184 struct omap_dss_device *dst)
188 dev_dbg(&dss->pdev->dev, "connect(%s, %s)\n",
189 src ? dev_name(src->dev) : "NULL",
190 dst ? dev_name(dst->dev) : "NULL");
194 * The destination is NULL when the source is connected to a
195 * bridge instead of a DSS device. Stop here, we will attach the
196 * bridge later when we will have a DRM encoder.
198 return src && src->bridge ? 0 : -EINVAL;
201 if (omapdss_device_is_connected(dst))
206 ret = dst->ops->connect(src, dst);
214 EXPORT_SYMBOL_GPL(omapdss_device_connect);
216 void omapdss_device_disconnect(struct omap_dss_device *src,
217 struct omap_dss_device *dst)
219 struct dss_device *dss = src ? src->dss : dst->dss;
221 dev_dbg(&dss->pdev->dev, "disconnect(%s, %s)\n",
222 src ? dev_name(src->dev) : "NULL",
223 dst ? dev_name(dst->dev) : "NULL");
226 WARN_ON(!src->bridge);
230 if (!dst->id && !omapdss_device_is_connected(dst)) {
231 WARN_ON(!dst->display);
235 WARN_ON(dst->state != OMAP_DSS_DISPLAY_DISABLED);
237 dst->ops->disconnect(src, dst);
240 EXPORT_SYMBOL_GPL(omapdss_device_disconnect);
242 void omapdss_device_pre_enable(struct omap_dss_device *dssdev)
247 omapdss_device_pre_enable(dssdev->next);
249 if (dssdev->ops->pre_enable)
250 dssdev->ops->pre_enable(dssdev);
252 EXPORT_SYMBOL_GPL(omapdss_device_pre_enable);
254 void omapdss_device_enable(struct omap_dss_device *dssdev)
259 if (dssdev->ops->enable)
260 dssdev->ops->enable(dssdev);
262 omapdss_device_enable(dssdev->next);
264 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
266 EXPORT_SYMBOL_GPL(omapdss_device_enable);
268 void omapdss_device_disable(struct omap_dss_device *dssdev)
273 omapdss_device_disable(dssdev->next);
275 if (dssdev->ops->disable)
276 dssdev->ops->disable(dssdev);
278 EXPORT_SYMBOL_GPL(omapdss_device_disable);
280 void omapdss_device_post_disable(struct omap_dss_device *dssdev)
285 if (dssdev->ops->post_disable)
286 dssdev->ops->post_disable(dssdev);
288 omapdss_device_post_disable(dssdev->next);
290 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
292 EXPORT_SYMBOL_GPL(omapdss_device_post_disable);
294 /* -----------------------------------------------------------------------------
295 * Components Handling
298 static struct list_head omapdss_comp_list;
300 struct omapdss_comp_node {
301 struct list_head list;
302 struct device_node *node;
303 bool dss_core_component;
306 static bool omapdss_list_contains(const struct device_node *node)
308 struct omapdss_comp_node *comp;
310 list_for_each_entry(comp, &omapdss_comp_list, list) {
311 if (comp->node == node)
318 static void omapdss_walk_device(struct device *dev, struct device_node *node,
321 struct device_node *n;
322 struct omapdss_comp_node *comp = devm_kzalloc(dev, sizeof(*comp),
327 comp->dss_core_component = dss_core;
328 list_add(&comp->list, &omapdss_comp_list);
332 * of_graph_get_remote_port_parent() prints an error if there is no
333 * port/ports node. To avoid that, check first that there's the node.
335 n = of_get_child_by_name(node, "ports");
337 n = of_get_child_by_name(node, "port");
344 while ((n = of_graph_get_next_endpoint(node, n)) != NULL) {
345 struct device_node *pn = of_graph_get_remote_port_parent(n);
350 if (!of_device_is_available(pn) || omapdss_list_contains(pn)) {
355 omapdss_walk_device(dev, pn, false);
359 void omapdss_gather_components(struct device *dev)
361 struct device_node *child;
363 INIT_LIST_HEAD(&omapdss_comp_list);
365 omapdss_walk_device(dev, dev->of_node, true);
367 for_each_available_child_of_node(dev->of_node, child) {
368 if (!of_find_property(child, "compatible", NULL))
371 omapdss_walk_device(dev, child, true);
374 EXPORT_SYMBOL(omapdss_gather_components);
376 static bool omapdss_component_is_loaded(struct omapdss_comp_node *comp)
378 if (comp->dss_core_component)
380 if (omapdss_device_is_registered(comp->node))
386 bool omapdss_stack_is_ready(void)
388 struct omapdss_comp_node *comp;
390 list_for_each_entry(comp, &omapdss_comp_list, list) {
391 if (!omapdss_component_is_loaded(comp))
397 EXPORT_SYMBOL(omapdss_stack_is_ready);
399 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
400 MODULE_DESCRIPTION("OMAP Display Subsystem Base");
401 MODULE_LICENSE("GPL v2");