base.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. /*
  2. * OMAP Display Subsystem Base
  3. *
  4. * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/
  5. *
  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.
  9. *
  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.
  14. */
  15. #include <linux/kernel.h>
  16. #include <linux/list.h>
  17. #include <linux/module.h>
  18. #include <linux/mutex.h>
  19. #include <linux/of.h>
  20. #include <linux/of_graph.h>
  21. #include "dss.h"
  22. #include "omapdss.h"
  23. static struct dss_device *dss_device;
  24. struct dss_device *omapdss_get_dss(void)
  25. {
  26. return dss_device;
  27. }
  28. EXPORT_SYMBOL(omapdss_get_dss);
  29. void omapdss_set_dss(struct dss_device *dss)
  30. {
  31. dss_device = dss;
  32. }
  33. EXPORT_SYMBOL(omapdss_set_dss);
  34. struct dispc_device *dispc_get_dispc(struct dss_device *dss)
  35. {
  36. return dss->dispc;
  37. }
  38. EXPORT_SYMBOL(dispc_get_dispc);
  39. const struct dispc_ops *dispc_get_ops(struct dss_device *dss)
  40. {
  41. return dss->dispc_ops;
  42. }
  43. EXPORT_SYMBOL(dispc_get_ops);
  44. /* -----------------------------------------------------------------------------
  45. * OMAP DSS Devices Handling
  46. */
  47. static LIST_HEAD(omapdss_devices_list);
  48. static DEFINE_MUTEX(omapdss_devices_lock);
  49. void omapdss_device_register(struct omap_dss_device *dssdev)
  50. {
  51. mutex_lock(&omapdss_devices_lock);
  52. list_add_tail(&dssdev->list, &omapdss_devices_list);
  53. mutex_unlock(&omapdss_devices_lock);
  54. }
  55. EXPORT_SYMBOL_GPL(omapdss_device_register);
  56. void omapdss_device_unregister(struct omap_dss_device *dssdev)
  57. {
  58. mutex_lock(&omapdss_devices_lock);
  59. list_del(&dssdev->list);
  60. mutex_unlock(&omapdss_devices_lock);
  61. }
  62. EXPORT_SYMBOL_GPL(omapdss_device_unregister);
  63. static bool omapdss_device_is_registered(struct device_node *node)
  64. {
  65. struct omap_dss_device *dssdev;
  66. bool found = false;
  67. mutex_lock(&omapdss_devices_lock);
  68. list_for_each_entry(dssdev, &omapdss_devices_list, list) {
  69. if (dssdev->dev->of_node == node) {
  70. found = true;
  71. break;
  72. }
  73. }
  74. mutex_unlock(&omapdss_devices_lock);
  75. return found;
  76. }
  77. struct omap_dss_device *omapdss_device_get(struct omap_dss_device *dssdev)
  78. {
  79. if (!try_module_get(dssdev->owner))
  80. return NULL;
  81. if (get_device(dssdev->dev) == NULL) {
  82. module_put(dssdev->owner);
  83. return NULL;
  84. }
  85. return dssdev;
  86. }
  87. EXPORT_SYMBOL(omapdss_device_get);
  88. void omapdss_device_put(struct omap_dss_device *dssdev)
  89. {
  90. put_device(dssdev->dev);
  91. module_put(dssdev->owner);
  92. }
  93. EXPORT_SYMBOL(omapdss_device_put);
  94. struct omap_dss_device *omapdss_find_device_by_port(struct device_node *src,
  95. unsigned int port)
  96. {
  97. struct omap_dss_device *dssdev;
  98. list_for_each_entry(dssdev, &omapdss_devices_list, list) {
  99. if (dssdev->dev->of_node == src && dssdev->of_ports & BIT(port))
  100. return omapdss_device_get(dssdev);
  101. }
  102. return NULL;
  103. }
  104. /*
  105. * Search for the next device starting at @from. The type argument specfies
  106. * which device types to consider when searching. Searching for multiple types
  107. * is supported by and'ing their type flags. Release the reference to the @from
  108. * device, and acquire a reference to the returned device if found.
  109. */
  110. struct omap_dss_device *omapdss_device_get_next(struct omap_dss_device *from,
  111. enum omap_dss_device_type type)
  112. {
  113. struct omap_dss_device *dssdev;
  114. struct list_head *list;
  115. mutex_lock(&omapdss_devices_lock);
  116. if (list_empty(&omapdss_devices_list)) {
  117. dssdev = NULL;
  118. goto done;
  119. }
  120. /*
  121. * Start from the from entry if given or from omapdss_devices_list
  122. * otherwise.
  123. */
  124. list = from ? &from->list : &omapdss_devices_list;
  125. list_for_each_entry(dssdev, list, list) {
  126. /*
  127. * Stop if we reach the omapdss_devices_list, that's the end of
  128. * the list.
  129. */
  130. if (&dssdev->list == &omapdss_devices_list) {
  131. dssdev = NULL;
  132. goto done;
  133. }
  134. /*
  135. * Accept display entities if the display type is requested,
  136. * and output entities if the output type is requested.
  137. */
  138. if ((type & OMAP_DSS_DEVICE_TYPE_DISPLAY) &&
  139. !dssdev->output_type)
  140. goto done;
  141. if ((type & OMAP_DSS_DEVICE_TYPE_OUTPUT) && dssdev->id &&
  142. dssdev->next)
  143. goto done;
  144. }
  145. dssdev = NULL;
  146. done:
  147. if (from)
  148. omapdss_device_put(from);
  149. if (dssdev)
  150. omapdss_device_get(dssdev);
  151. mutex_unlock(&omapdss_devices_lock);
  152. return dssdev;
  153. }
  154. EXPORT_SYMBOL(omapdss_device_get_next);
  155. int omapdss_device_connect(struct dss_device *dss,
  156. struct omap_dss_device *src,
  157. struct omap_dss_device *dst)
  158. {
  159. int ret;
  160. dev_dbg(dst->dev, "connect\n");
  161. if (omapdss_device_is_connected(dst))
  162. return -EBUSY;
  163. dst->dss = dss;
  164. ret = dst->ops->connect(src, dst);
  165. if (ret < 0) {
  166. dst->dss = NULL;
  167. return ret;
  168. }
  169. if (src) {
  170. WARN_ON(src->dst);
  171. dst->src = src;
  172. src->dst = dst;
  173. }
  174. return 0;
  175. }
  176. EXPORT_SYMBOL_GPL(omapdss_device_connect);
  177. void omapdss_device_disconnect(struct omap_dss_device *src,
  178. struct omap_dss_device *dst)
  179. {
  180. dev_dbg(dst->dev, "disconnect\n");
  181. if (!dst->id && !omapdss_device_is_connected(dst)) {
  182. WARN_ON(dst->output_type);
  183. return;
  184. }
  185. if (src) {
  186. if (WARN_ON(dst != src->dst))
  187. return;
  188. dst->src = NULL;
  189. src->dst = NULL;
  190. }
  191. WARN_ON(dst->state != OMAP_DSS_DISPLAY_DISABLED);
  192. dst->ops->disconnect(src, dst);
  193. dst->dss = NULL;
  194. }
  195. EXPORT_SYMBOL_GPL(omapdss_device_disconnect);
  196. /* -----------------------------------------------------------------------------
  197. * Components Handling
  198. */
  199. static struct list_head omapdss_comp_list;
  200. struct omapdss_comp_node {
  201. struct list_head list;
  202. struct device_node *node;
  203. bool dss_core_component;
  204. };
  205. static bool omapdss_list_contains(const struct device_node *node)
  206. {
  207. struct omapdss_comp_node *comp;
  208. list_for_each_entry(comp, &omapdss_comp_list, list) {
  209. if (comp->node == node)
  210. return true;
  211. }
  212. return false;
  213. }
  214. static void omapdss_walk_device(struct device *dev, struct device_node *node,
  215. bool dss_core)
  216. {
  217. struct device_node *n;
  218. struct omapdss_comp_node *comp = devm_kzalloc(dev, sizeof(*comp),
  219. GFP_KERNEL);
  220. if (comp) {
  221. comp->node = node;
  222. comp->dss_core_component = dss_core;
  223. list_add(&comp->list, &omapdss_comp_list);
  224. }
  225. /*
  226. * of_graph_get_remote_port_parent() prints an error if there is no
  227. * port/ports node. To avoid that, check first that there's the node.
  228. */
  229. n = of_get_child_by_name(node, "ports");
  230. if (!n)
  231. n = of_get_child_by_name(node, "port");
  232. if (!n)
  233. return;
  234. of_node_put(n);
  235. n = NULL;
  236. while ((n = of_graph_get_next_endpoint(node, n)) != NULL) {
  237. struct device_node *pn = of_graph_get_remote_port_parent(n);
  238. if (!pn)
  239. continue;
  240. if (!of_device_is_available(pn) || omapdss_list_contains(pn)) {
  241. of_node_put(pn);
  242. continue;
  243. }
  244. omapdss_walk_device(dev, pn, false);
  245. }
  246. }
  247. void omapdss_gather_components(struct device *dev)
  248. {
  249. struct device_node *child;
  250. INIT_LIST_HEAD(&omapdss_comp_list);
  251. omapdss_walk_device(dev, dev->of_node, true);
  252. for_each_available_child_of_node(dev->of_node, child) {
  253. if (!of_find_property(child, "compatible", NULL))
  254. continue;
  255. omapdss_walk_device(dev, child, true);
  256. }
  257. }
  258. EXPORT_SYMBOL(omapdss_gather_components);
  259. static bool omapdss_component_is_loaded(struct omapdss_comp_node *comp)
  260. {
  261. if (comp->dss_core_component)
  262. return true;
  263. if (omapdss_device_is_registered(comp->node))
  264. return true;
  265. return false;
  266. }
  267. bool omapdss_stack_is_ready(void)
  268. {
  269. struct omapdss_comp_node *comp;
  270. list_for_each_entry(comp, &omapdss_comp_list, list) {
  271. if (!omapdss_component_is_loaded(comp))
  272. return false;
  273. }
  274. return true;
  275. }
  276. EXPORT_SYMBOL(omapdss_stack_is_ready);
  277. MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
  278. MODULE_DESCRIPTION("OMAP Display Subsystem Base");
  279. MODULE_LICENSE("GPL v2");