root/drivers/gpu/drm/omapdrm/dss/base.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. omapdss_get_dss
  2. omapdss_set_dss
  3. dispc_get_dispc
  4. dispc_get_ops
  5. omapdss_device_register
  6. omapdss_device_unregister
  7. omapdss_device_is_registered
  8. omapdss_device_get
  9. omapdss_device_put
  10. omapdss_find_device_by_node
  11. omapdss_device_next_output
  12. omapdss_device_is_connected
  13. omapdss_device_connect
  14. omapdss_device_disconnect
  15. omapdss_device_pre_enable
  16. omapdss_device_enable
  17. omapdss_device_disable
  18. omapdss_device_post_disable
  19. omapdss_list_contains
  20. omapdss_walk_device
  21. omapdss_gather_components
  22. omapdss_component_is_loaded
  23. omapdss_stack_is_ready

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * OMAP Display Subsystem Base
   4  *
   5  * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/
   6  */
   7 
   8 #include <linux/kernel.h>
   9 #include <linux/list.h>
  10 #include <linux/module.h>
  11 #include <linux/mutex.h>
  12 #include <linux/of.h>
  13 #include <linux/of_graph.h>
  14 #include <linux/platform_device.h>
  15 
  16 #include "dss.h"
  17 #include "omapdss.h"
  18 
  19 static struct dss_device *dss_device;
  20 
  21 struct dss_device *omapdss_get_dss(void)
  22 {
  23         return dss_device;
  24 }
  25 EXPORT_SYMBOL(omapdss_get_dss);
  26 
  27 void omapdss_set_dss(struct dss_device *dss)
  28 {
  29         dss_device = dss;
  30 }
  31 EXPORT_SYMBOL(omapdss_set_dss);
  32 
  33 struct dispc_device *dispc_get_dispc(struct dss_device *dss)
  34 {
  35         return dss->dispc;
  36 }
  37 EXPORT_SYMBOL(dispc_get_dispc);
  38 
  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 
  46 /* -----------------------------------------------------------------------------
  47  * OMAP DSS Devices Handling
  48  */
  49 
  50 static LIST_HEAD(omapdss_devices_list);
  51 static DEFINE_MUTEX(omapdss_devices_lock);
  52 
  53 void omapdss_device_register(struct omap_dss_device *dssdev)
  54 {
  55         mutex_lock(&omapdss_devices_lock);
  56         list_add_tail(&dssdev->list, &omapdss_devices_list);
  57         mutex_unlock(&omapdss_devices_lock);
  58 }
  59 EXPORT_SYMBOL_GPL(omapdss_device_register);
  60 
  61 void omapdss_device_unregister(struct omap_dss_device *dssdev)
  62 {
  63         mutex_lock(&omapdss_devices_lock);
  64         list_del(&dssdev->list);
  65         mutex_unlock(&omapdss_devices_lock);
  66 }
  67 EXPORT_SYMBOL_GPL(omapdss_device_unregister);
  68 
  69 static bool omapdss_device_is_registered(struct device_node *node)
  70 {
  71         struct omap_dss_device *dssdev;
  72         bool found = false;
  73 
  74         mutex_lock(&omapdss_devices_lock);
  75 
  76         list_for_each_entry(dssdev, &omapdss_devices_list, list) {
  77                 if (dssdev->dev->of_node == node) {
  78                         found = true;
  79                         break;
  80                 }
  81         }
  82 
  83         mutex_unlock(&omapdss_devices_lock);
  84         return found;
  85 }
  86 
  87 struct omap_dss_device *omapdss_device_get(struct omap_dss_device *dssdev)
  88 {
  89         if (!try_module_get(dssdev->owner))
  90                 return NULL;
  91 
  92         if (get_device(dssdev->dev) == NULL) {
  93                 module_put(dssdev->owner);
  94                 return NULL;
  95         }
  96 
  97         return dssdev;
  98 }
  99 EXPORT_SYMBOL(omapdss_device_get);
 100 
 101 void omapdss_device_put(struct omap_dss_device *dssdev)
 102 {
 103         put_device(dssdev->dev);
 104         module_put(dssdev->owner);
 105 }
 106 EXPORT_SYMBOL(omapdss_device_put);
 107 
 108 struct omap_dss_device *omapdss_find_device_by_node(struct device_node *node)
 109 {
 110         struct omap_dss_device *dssdev;
 111 
 112         list_for_each_entry(dssdev, &omapdss_devices_list, list) {
 113                 if (dssdev->dev->of_node == node)
 114                         return omapdss_device_get(dssdev);
 115         }
 116 
 117         return NULL;
 118 }
 119 
 120 /*
 121  * Search for the next output device starting at @from. Release the reference to
 122  * the @from device, and acquire a reference to the returned device if found.
 123  */
 124 struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from)
 125 {
 126         struct omap_dss_device *dssdev;
 127         struct list_head *list;
 128 
 129         mutex_lock(&omapdss_devices_lock);
 130 
 131         if (list_empty(&omapdss_devices_list)) {
 132                 dssdev = NULL;
 133                 goto done;
 134         }
 135 
 136         /*
 137          * Start from the from entry if given or from omapdss_devices_list
 138          * otherwise.
 139          */
 140         list = from ? &from->list : &omapdss_devices_list;
 141 
 142         list_for_each_entry(dssdev, list, list) {
 143                 /*
 144                  * Stop if we reach the omapdss_devices_list, that's the end of
 145                  * the list.
 146                  */
 147                 if (&dssdev->list == &omapdss_devices_list) {
 148                         dssdev = NULL;
 149                         goto done;
 150                 }
 151 
 152                 if (dssdev->id &&
 153                     (dssdev->next || dssdev->bridge || dssdev->panel))
 154                         goto done;
 155         }
 156 
 157         dssdev = NULL;
 158 
 159 done:
 160         if (from)
 161                 omapdss_device_put(from);
 162         if (dssdev)
 163                 omapdss_device_get(dssdev);
 164 
 165         mutex_unlock(&omapdss_devices_lock);
 166         return dssdev;
 167 }
 168 EXPORT_SYMBOL(omapdss_device_next_output);
 169 
 170 static bool omapdss_device_is_connected(struct omap_dss_device *dssdev)
 171 {
 172         return dssdev->dss;
 173 }
 174 
 175 int omapdss_device_connect(struct dss_device *dss,
 176                            struct omap_dss_device *src,
 177                            struct omap_dss_device *dst)
 178 {
 179         int ret;
 180 
 181         dev_dbg(&dss->pdev->dev, "connect(%s, %s)\n",
 182                 src ? dev_name(src->dev) : "NULL",
 183                 dst ? dev_name(dst->dev) : "NULL");
 184 
 185         if (!dst) {
 186                 /*
 187                  * The destination is NULL when the source is connected to a
 188                  * bridge or panel instead of a DSS device. Stop here, we will
 189                  * attach the bridge or panel later when we will have a DRM
 190                  * encoder.
 191                  */
 192                 return src && (src->bridge || src->panel) ? 0 : -EINVAL;
 193         }
 194 
 195         if (omapdss_device_is_connected(dst))
 196                 return -EBUSY;
 197 
 198         dst->dss = dss;
 199 
 200         ret = dst->ops->connect(src, dst);
 201         if (ret < 0) {
 202                 dst->dss = NULL;
 203                 return ret;
 204         }
 205 
 206         return 0;
 207 }
 208 EXPORT_SYMBOL_GPL(omapdss_device_connect);
 209 
 210 void omapdss_device_disconnect(struct omap_dss_device *src,
 211                                struct omap_dss_device *dst)
 212 {
 213         struct dss_device *dss = src ? src->dss : dst->dss;
 214 
 215         dev_dbg(&dss->pdev->dev, "disconnect(%s, %s)\n",
 216                 src ? dev_name(src->dev) : "NULL",
 217                 dst ? dev_name(dst->dev) : "NULL");
 218 
 219         if (!dst) {
 220                 WARN_ON(!src->bridge && !src->panel);
 221                 return;
 222         }
 223 
 224         if (!dst->id && !omapdss_device_is_connected(dst)) {
 225                 WARN_ON(!dst->display);
 226                 return;
 227         }
 228 
 229         WARN_ON(dst->state != OMAP_DSS_DISPLAY_DISABLED);
 230 
 231         dst->ops->disconnect(src, dst);
 232         dst->dss = NULL;
 233 }
 234 EXPORT_SYMBOL_GPL(omapdss_device_disconnect);
 235 
 236 void omapdss_device_pre_enable(struct omap_dss_device *dssdev)
 237 {
 238         if (!dssdev)
 239                 return;
 240 
 241         omapdss_device_pre_enable(dssdev->next);
 242 
 243         if (dssdev->ops->pre_enable)
 244                 dssdev->ops->pre_enable(dssdev);
 245 }
 246 EXPORT_SYMBOL_GPL(omapdss_device_pre_enable);
 247 
 248 void omapdss_device_enable(struct omap_dss_device *dssdev)
 249 {
 250         if (!dssdev)
 251                 return;
 252 
 253         if (dssdev->ops->enable)
 254                 dssdev->ops->enable(dssdev);
 255 
 256         omapdss_device_enable(dssdev->next);
 257 
 258         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 259 }
 260 EXPORT_SYMBOL_GPL(omapdss_device_enable);
 261 
 262 void omapdss_device_disable(struct omap_dss_device *dssdev)
 263 {
 264         if (!dssdev)
 265                 return;
 266 
 267         omapdss_device_disable(dssdev->next);
 268 
 269         if (dssdev->ops->disable)
 270                 dssdev->ops->disable(dssdev);
 271 }
 272 EXPORT_SYMBOL_GPL(omapdss_device_disable);
 273 
 274 void omapdss_device_post_disable(struct omap_dss_device *dssdev)
 275 {
 276         if (!dssdev)
 277                 return;
 278 
 279         if (dssdev->ops->post_disable)
 280                 dssdev->ops->post_disable(dssdev);
 281 
 282         omapdss_device_post_disable(dssdev->next);
 283 
 284         dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 285 }
 286 EXPORT_SYMBOL_GPL(omapdss_device_post_disable);
 287 
 288 /* -----------------------------------------------------------------------------
 289  * Components Handling
 290  */
 291 
 292 static struct list_head omapdss_comp_list;
 293 
 294 struct omapdss_comp_node {
 295         struct list_head list;
 296         struct device_node *node;
 297         bool dss_core_component;
 298         const char *compat;
 299 };
 300 
 301 static bool omapdss_list_contains(const struct device_node *node)
 302 {
 303         struct omapdss_comp_node *comp;
 304 
 305         list_for_each_entry(comp, &omapdss_comp_list, list) {
 306                 if (comp->node == node)
 307                         return true;
 308         }
 309 
 310         return false;
 311 }
 312 
 313 static void omapdss_walk_device(struct device *dev, struct device_node *node,
 314                                 bool dss_core)
 315 {
 316         struct omapdss_comp_node *comp;
 317         struct device_node *n;
 318         const char *compat;
 319         int ret;
 320 
 321         ret = of_property_read_string(node, "compatible", &compat);
 322         if (ret < 0)
 323                 return;
 324 
 325         comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
 326         if (comp) {
 327                 comp->node = node;
 328                 comp->dss_core_component = dss_core;
 329                 comp->compat = compat;
 330                 list_add(&comp->list, &omapdss_comp_list);
 331         }
 332 
 333         /*
 334          * of_graph_get_remote_port_parent() prints an error if there is no
 335          * port/ports node. To avoid that, check first that there's the node.
 336          */
 337         n = of_get_child_by_name(node, "ports");
 338         if (!n)
 339                 n = of_get_child_by_name(node, "port");
 340         if (!n)
 341                 return;
 342 
 343         of_node_put(n);
 344 
 345         n = NULL;
 346         while ((n = of_graph_get_next_endpoint(node, n)) != NULL) {
 347                 struct device_node *pn = of_graph_get_remote_port_parent(n);
 348 
 349                 if (!pn)
 350                         continue;
 351 
 352                 if (!of_device_is_available(pn) || omapdss_list_contains(pn)) {
 353                         of_node_put(pn);
 354                         continue;
 355                 }
 356 
 357                 omapdss_walk_device(dev, pn, false);
 358         }
 359 }
 360 
 361 void omapdss_gather_components(struct device *dev)
 362 {
 363         struct device_node *child;
 364 
 365         INIT_LIST_HEAD(&omapdss_comp_list);
 366 
 367         omapdss_walk_device(dev, dev->of_node, true);
 368 
 369         for_each_available_child_of_node(dev->of_node, child)
 370                 omapdss_walk_device(dev, child, true);
 371 }
 372 EXPORT_SYMBOL(omapdss_gather_components);
 373 
 374 static bool omapdss_component_is_loaded(struct omapdss_comp_node *comp)
 375 {
 376         if (comp->dss_core_component)
 377                 return true;
 378         if (!strstarts(comp->compat, "omapdss,"))
 379                 return true;
 380         if (omapdss_device_is_registered(comp->node))
 381                 return true;
 382 
 383         return false;
 384 }
 385 
 386 bool omapdss_stack_is_ready(void)
 387 {
 388         struct omapdss_comp_node *comp;
 389 
 390         list_for_each_entry(comp, &omapdss_comp_list, list) {
 391                 if (!omapdss_component_is_loaded(comp))
 392                         return false;
 393         }
 394 
 395         return true;
 396 }
 397 EXPORT_SYMBOL(omapdss_stack_is_ready);
 398 
 399 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
 400 MODULE_DESCRIPTION("OMAP Display Subsystem Base");
 401 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */