1bb5cdf8dSAndrew F. Davis /* 2bb5cdf8dSAndrew F. Davis * OMAP Display Subsystem Base 3bb5cdf8dSAndrew F. Davis * 4bb5cdf8dSAndrew F. Davis * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/ 5bb5cdf8dSAndrew F. Davis * 6bb5cdf8dSAndrew F. Davis * This program is free software; you can redistribute it and/or modify 7bb5cdf8dSAndrew F. Davis * it under the terms of the GNU General Public License version 2 as 8bb5cdf8dSAndrew F. Davis * published by the Free Software Foundation. 9bb5cdf8dSAndrew F. Davis * 10bb5cdf8dSAndrew F. Davis * This program is distributed in the hope that it will be useful, but 11bb5cdf8dSAndrew F. Davis * WITHOUT ANY WARRANTY; without even the implied warranty of 12bb5cdf8dSAndrew F. Davis * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13bb5cdf8dSAndrew F. Davis * General Public License for more details. 14bb5cdf8dSAndrew F. Davis */ 15bb5cdf8dSAndrew F. Davis 16a99ac0d9STomi Valkeinen #include <linux/kernel.h> 176a7c5a22SLaurent Pinchart #include <linux/list.h> 18a99ac0d9STomi Valkeinen #include <linux/module.h> 196a7c5a22SLaurent Pinchart #include <linux/mutex.h> 201e08c822SPeter Ujfalusi #include <linux/of.h> 211e08c822SPeter Ujfalusi #include <linux/of_graph.h> 22d3541ca8SLaurent Pinchart 23d3541ca8SLaurent Pinchart #include "dss.h" 241e08c822SPeter Ujfalusi #include "omapdss.h" 25a99ac0d9STomi Valkeinen 2672877cf3SLaurent Pinchart static struct dss_device *dss_device; 277c299716STomi Valkeinen 2872877cf3SLaurent Pinchart struct dss_device *omapdss_get_dss(void) 297c299716STomi Valkeinen { 3072877cf3SLaurent Pinchart return dss_device; 317c299716STomi Valkeinen } 3272877cf3SLaurent Pinchart EXPORT_SYMBOL(omapdss_get_dss); 337c299716STomi Valkeinen 3472877cf3SLaurent Pinchart void omapdss_set_dss(struct dss_device *dss) 357c299716STomi Valkeinen { 3672877cf3SLaurent Pinchart dss_device = dss; 377c299716STomi Valkeinen } 3872877cf3SLaurent Pinchart EXPORT_SYMBOL(omapdss_set_dss); 397c299716STomi Valkeinen 4050638ae5SLaurent Pinchart struct dispc_device *dispc_get_dispc(struct dss_device *dss) 4150638ae5SLaurent Pinchart { 4250638ae5SLaurent Pinchart return dss->dispc; 4350638ae5SLaurent Pinchart } 4450638ae5SLaurent Pinchart EXPORT_SYMBOL(dispc_get_dispc); 4550638ae5SLaurent Pinchart 46d3541ca8SLaurent Pinchart const struct dispc_ops *dispc_get_ops(struct dss_device *dss) 478a13398cSTomi Valkeinen { 48d3541ca8SLaurent Pinchart return dss->dispc_ops; 498a13398cSTomi Valkeinen } 508a13398cSTomi Valkeinen EXPORT_SYMBOL(dispc_get_ops); 518a13398cSTomi Valkeinen 526a7c5a22SLaurent Pinchart 536a7c5a22SLaurent Pinchart /* ----------------------------------------------------------------------------- 546a7c5a22SLaurent Pinchart * OMAP DSS Devices Handling 556a7c5a22SLaurent Pinchart */ 566a7c5a22SLaurent Pinchart 576a7c5a22SLaurent Pinchart static LIST_HEAD(omapdss_devices_list); 586a7c5a22SLaurent Pinchart static DEFINE_MUTEX(omapdss_devices_lock); 596a7c5a22SLaurent Pinchart 606a7c5a22SLaurent Pinchart void omapdss_device_register(struct omap_dss_device *dssdev) 616a7c5a22SLaurent Pinchart { 626a7c5a22SLaurent Pinchart mutex_lock(&omapdss_devices_lock); 636a7c5a22SLaurent Pinchart list_add_tail(&dssdev->list, &omapdss_devices_list); 646a7c5a22SLaurent Pinchart mutex_unlock(&omapdss_devices_lock); 656a7c5a22SLaurent Pinchart } 666a7c5a22SLaurent Pinchart 676a7c5a22SLaurent Pinchart void omapdss_device_unregister(struct omap_dss_device *dssdev) 686a7c5a22SLaurent Pinchart { 696a7c5a22SLaurent Pinchart mutex_lock(&omapdss_devices_lock); 706a7c5a22SLaurent Pinchart list_del(&dssdev->list); 716a7c5a22SLaurent Pinchart mutex_unlock(&omapdss_devices_lock); 726a7c5a22SLaurent Pinchart } 736a7c5a22SLaurent Pinchart 749184f8d9SLaurent Pinchart static bool omapdss_device_is_registered(struct device_node *node) 759184f8d9SLaurent Pinchart { 769184f8d9SLaurent Pinchart struct omap_dss_device *dssdev; 779184f8d9SLaurent Pinchart bool found = false; 789184f8d9SLaurent Pinchart 799184f8d9SLaurent Pinchart mutex_lock(&omapdss_devices_lock); 809184f8d9SLaurent Pinchart 819184f8d9SLaurent Pinchart list_for_each_entry(dssdev, &omapdss_devices_list, list) { 829184f8d9SLaurent Pinchart if (dssdev->dev->of_node == node) { 839184f8d9SLaurent Pinchart found = true; 849184f8d9SLaurent Pinchart break; 859184f8d9SLaurent Pinchart } 869184f8d9SLaurent Pinchart } 879184f8d9SLaurent Pinchart 889184f8d9SLaurent Pinchart mutex_unlock(&omapdss_devices_lock); 899184f8d9SLaurent Pinchart return found; 909184f8d9SLaurent Pinchart } 919184f8d9SLaurent Pinchart 92e10bd354SLaurent Pinchart struct omap_dss_device *omapdss_find_device_by_port(struct device_node *src, 93e10bd354SLaurent Pinchart unsigned int port) 94e10bd354SLaurent Pinchart { 95e10bd354SLaurent Pinchart struct omap_dss_device *dssdev; 96e10bd354SLaurent Pinchart 97e10bd354SLaurent Pinchart list_for_each_entry(dssdev, &omapdss_devices_list, list) { 98e10bd354SLaurent Pinchart if (dssdev->dev->of_node == src && dssdev->port_num == port) 99e10bd354SLaurent Pinchart return omap_dss_get_device(dssdev); 100e10bd354SLaurent Pinchart } 101e10bd354SLaurent Pinchart 102e10bd354SLaurent Pinchart return NULL; 103e10bd354SLaurent Pinchart } 104e10bd354SLaurent Pinchart 105ec727e3fSLaurent Pinchart int omapdss_device_connect(struct omap_dss_device *src, 106ec727e3fSLaurent Pinchart struct omap_dss_device *dst) 107ec727e3fSLaurent Pinchart { 108*1f507968SLaurent Pinchart dev_dbg(src->dev, "connect\n"); 109*1f507968SLaurent Pinchart 110*1f507968SLaurent Pinchart if (omapdss_device_is_connected(src)) 111*1f507968SLaurent Pinchart return -EBUSY; 112*1f507968SLaurent Pinchart 113ec727e3fSLaurent Pinchart if (src->driver) 114ec727e3fSLaurent Pinchart return src->driver->connect(src); 115ec727e3fSLaurent Pinchart else 116ec727e3fSLaurent Pinchart return src->ops->connect(src, dst); 117ec727e3fSLaurent Pinchart } 118ec727e3fSLaurent Pinchart EXPORT_SYMBOL_GPL(omapdss_device_connect); 119ec727e3fSLaurent Pinchart 120ec727e3fSLaurent Pinchart void omapdss_device_disconnect(struct omap_dss_device *src, 121ec727e3fSLaurent Pinchart struct omap_dss_device *dst) 122ec727e3fSLaurent Pinchart { 123*1f507968SLaurent Pinchart dev_dbg(src->dev, "disconnect\n"); 124*1f507968SLaurent Pinchart 125*1f507968SLaurent Pinchart if (!src->id && !omapdss_device_is_connected(src)) { 126*1f507968SLaurent Pinchart WARN_ON(!src->driver); 127*1f507968SLaurent Pinchart return; 128*1f507968SLaurent Pinchart } 129*1f507968SLaurent Pinchart 130ec727e3fSLaurent Pinchart if (src->driver) 131ec727e3fSLaurent Pinchart src->driver->disconnect(src); 132ec727e3fSLaurent Pinchart else 133ec727e3fSLaurent Pinchart src->ops->disconnect(src, dst); 134ec727e3fSLaurent Pinchart } 135ec727e3fSLaurent Pinchart EXPORT_SYMBOL_GPL(omapdss_device_disconnect); 136ec727e3fSLaurent Pinchart 1376a7c5a22SLaurent Pinchart /* ----------------------------------------------------------------------------- 1386a7c5a22SLaurent Pinchart * Components Handling 1396a7c5a22SLaurent Pinchart */ 1406a7c5a22SLaurent Pinchart 1416a7c5a22SLaurent Pinchart static struct list_head omapdss_comp_list; 1426a7c5a22SLaurent Pinchart 1436a7c5a22SLaurent Pinchart struct omapdss_comp_node { 1446a7c5a22SLaurent Pinchart struct list_head list; 1456a7c5a22SLaurent Pinchart struct device_node *node; 1466a7c5a22SLaurent Pinchart bool dss_core_component; 1476a7c5a22SLaurent Pinchart }; 1486a7c5a22SLaurent Pinchart 1491e08c822SPeter Ujfalusi static bool omapdss_list_contains(const struct device_node *node) 1501e08c822SPeter Ujfalusi { 1511e08c822SPeter Ujfalusi struct omapdss_comp_node *comp; 1521e08c822SPeter Ujfalusi 1531e08c822SPeter Ujfalusi list_for_each_entry(comp, &omapdss_comp_list, list) { 1541e08c822SPeter Ujfalusi if (comp->node == node) 1551e08c822SPeter Ujfalusi return true; 1561e08c822SPeter Ujfalusi } 1571e08c822SPeter Ujfalusi 1581e08c822SPeter Ujfalusi return false; 1591e08c822SPeter Ujfalusi } 1601e08c822SPeter Ujfalusi 1611e08c822SPeter Ujfalusi static void omapdss_walk_device(struct device *dev, struct device_node *node, 1621e08c822SPeter Ujfalusi bool dss_core) 1631e08c822SPeter Ujfalusi { 1641e08c822SPeter Ujfalusi struct device_node *n; 1651e08c822SPeter Ujfalusi struct omapdss_comp_node *comp = devm_kzalloc(dev, sizeof(*comp), 1661e08c822SPeter Ujfalusi GFP_KERNEL); 1671e08c822SPeter Ujfalusi 1681e08c822SPeter Ujfalusi if (comp) { 1691e08c822SPeter Ujfalusi comp->node = node; 1701e08c822SPeter Ujfalusi comp->dss_core_component = dss_core; 1711e08c822SPeter Ujfalusi list_add(&comp->list, &omapdss_comp_list); 1721e08c822SPeter Ujfalusi } 1731e08c822SPeter Ujfalusi 1741e08c822SPeter Ujfalusi /* 1751e08c822SPeter Ujfalusi * of_graph_get_remote_port_parent() prints an error if there is no 1761e08c822SPeter Ujfalusi * port/ports node. To avoid that, check first that there's the node. 1771e08c822SPeter Ujfalusi */ 1781e08c822SPeter Ujfalusi n = of_get_child_by_name(node, "ports"); 1791e08c822SPeter Ujfalusi if (!n) 1801e08c822SPeter Ujfalusi n = of_get_child_by_name(node, "port"); 1811e08c822SPeter Ujfalusi if (!n) 1821e08c822SPeter Ujfalusi return; 1831e08c822SPeter Ujfalusi 1841e08c822SPeter Ujfalusi of_node_put(n); 1851e08c822SPeter Ujfalusi 1861e08c822SPeter Ujfalusi n = NULL; 1871e08c822SPeter Ujfalusi while ((n = of_graph_get_next_endpoint(node, n)) != NULL) { 1881e08c822SPeter Ujfalusi struct device_node *pn = of_graph_get_remote_port_parent(n); 1891e08c822SPeter Ujfalusi 1901e08c822SPeter Ujfalusi if (!pn) 1911e08c822SPeter Ujfalusi continue; 1921e08c822SPeter Ujfalusi 1931e08c822SPeter Ujfalusi if (!of_device_is_available(pn) || omapdss_list_contains(pn)) { 1941e08c822SPeter Ujfalusi of_node_put(pn); 1951e08c822SPeter Ujfalusi continue; 1961e08c822SPeter Ujfalusi } 1971e08c822SPeter Ujfalusi 1981e08c822SPeter Ujfalusi omapdss_walk_device(dev, pn, false); 1991e08c822SPeter Ujfalusi } 2001e08c822SPeter Ujfalusi } 2011e08c822SPeter Ujfalusi 2021e08c822SPeter Ujfalusi void omapdss_gather_components(struct device *dev) 2031e08c822SPeter Ujfalusi { 2041e08c822SPeter Ujfalusi struct device_node *child; 2051e08c822SPeter Ujfalusi 2061e08c822SPeter Ujfalusi INIT_LIST_HEAD(&omapdss_comp_list); 2071e08c822SPeter Ujfalusi 2081e08c822SPeter Ujfalusi omapdss_walk_device(dev, dev->of_node, true); 2091e08c822SPeter Ujfalusi 2101e08c822SPeter Ujfalusi for_each_available_child_of_node(dev->of_node, child) { 2111e08c822SPeter Ujfalusi if (!of_find_property(child, "compatible", NULL)) 2121e08c822SPeter Ujfalusi continue; 2131e08c822SPeter Ujfalusi 2141e08c822SPeter Ujfalusi omapdss_walk_device(dev, child, true); 2151e08c822SPeter Ujfalusi } 2161e08c822SPeter Ujfalusi } 2171e08c822SPeter Ujfalusi EXPORT_SYMBOL(omapdss_gather_components); 2181e08c822SPeter Ujfalusi 2191e08c822SPeter Ujfalusi static bool omapdss_component_is_loaded(struct omapdss_comp_node *comp) 2201e08c822SPeter Ujfalusi { 2211e08c822SPeter Ujfalusi if (comp->dss_core_component) 2221e08c822SPeter Ujfalusi return true; 2239184f8d9SLaurent Pinchart if (omapdss_device_is_registered(comp->node)) 2241e08c822SPeter Ujfalusi return true; 2251e08c822SPeter Ujfalusi 2261e08c822SPeter Ujfalusi return false; 2271e08c822SPeter Ujfalusi } 2281e08c822SPeter Ujfalusi 2291e08c822SPeter Ujfalusi bool omapdss_stack_is_ready(void) 2301e08c822SPeter Ujfalusi { 2311e08c822SPeter Ujfalusi struct omapdss_comp_node *comp; 2321e08c822SPeter Ujfalusi 2331e08c822SPeter Ujfalusi list_for_each_entry(comp, &omapdss_comp_list, list) { 2341e08c822SPeter Ujfalusi if (!omapdss_component_is_loaded(comp)) 2351e08c822SPeter Ujfalusi return false; 2361e08c822SPeter Ujfalusi } 2371e08c822SPeter Ujfalusi 2381e08c822SPeter Ujfalusi return true; 2391e08c822SPeter Ujfalusi } 2401e08c822SPeter Ujfalusi EXPORT_SYMBOL(omapdss_stack_is_ready); 2411e08c822SPeter Ujfalusi 242a99ac0d9STomi Valkeinen MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); 243a99ac0d9STomi Valkeinen MODULE_DESCRIPTION("OMAP Display Subsystem Base"); 244a99ac0d9STomi Valkeinen MODULE_LICENSE("GPL v2"); 245