Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * OMAP Display Subsystem Base
0004  *
0005  * Copyright (C) 2015-2017 Texas Instruments Incorporated - https://www.ti.com/
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/list.h>
0010 #include <linux/module.h>
0011 #include <linux/mutex.h>
0012 #include <linux/of.h>
0013 #include <linux/of_graph.h>
0014 #include <linux/platform_device.h>
0015 
0016 #include "dss.h"
0017 #include "omapdss.h"
0018 
0019 struct dispc_device *dispc_get_dispc(struct dss_device *dss)
0020 {
0021     return dss->dispc;
0022 }
0023 
0024 /* -----------------------------------------------------------------------------
0025  * OMAP DSS Devices Handling
0026  */
0027 
0028 static LIST_HEAD(omapdss_devices_list);
0029 static DEFINE_MUTEX(omapdss_devices_lock);
0030 
0031 void omapdss_device_register(struct omap_dss_device *dssdev)
0032 {
0033     mutex_lock(&omapdss_devices_lock);
0034     list_add_tail(&dssdev->list, &omapdss_devices_list);
0035     mutex_unlock(&omapdss_devices_lock);
0036 }
0037 
0038 void omapdss_device_unregister(struct omap_dss_device *dssdev)
0039 {
0040     mutex_lock(&omapdss_devices_lock);
0041     list_del(&dssdev->list);
0042     mutex_unlock(&omapdss_devices_lock);
0043 }
0044 
0045 static bool omapdss_device_is_registered(struct device_node *node)
0046 {
0047     struct omap_dss_device *dssdev;
0048     bool found = false;
0049 
0050     mutex_lock(&omapdss_devices_lock);
0051 
0052     list_for_each_entry(dssdev, &omapdss_devices_list, list) {
0053         if (dssdev->dev->of_node == node) {
0054             found = true;
0055             break;
0056         }
0057     }
0058 
0059     mutex_unlock(&omapdss_devices_lock);
0060     return found;
0061 }
0062 
0063 struct omap_dss_device *omapdss_device_get(struct omap_dss_device *dssdev)
0064 {
0065     if (get_device(dssdev->dev) == NULL)
0066         return NULL;
0067 
0068     return dssdev;
0069 }
0070 
0071 void omapdss_device_put(struct omap_dss_device *dssdev)
0072 {
0073     put_device(dssdev->dev);
0074 }
0075 
0076 struct omap_dss_device *omapdss_find_device_by_node(struct device_node *node)
0077 {
0078     struct omap_dss_device *dssdev;
0079 
0080     list_for_each_entry(dssdev, &omapdss_devices_list, list) {
0081         if (dssdev->dev->of_node == node)
0082             return omapdss_device_get(dssdev);
0083     }
0084 
0085     return NULL;
0086 }
0087 
0088 /*
0089  * Search for the next output device starting at @from. Release the reference to
0090  * the @from device, and acquire a reference to the returned device if found.
0091  */
0092 struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from)
0093 {
0094     struct omap_dss_device *dssdev;
0095     struct list_head *list;
0096 
0097     mutex_lock(&omapdss_devices_lock);
0098 
0099     if (list_empty(&omapdss_devices_list)) {
0100         dssdev = NULL;
0101         goto done;
0102     }
0103 
0104     /*
0105      * Start from the from entry if given or from omapdss_devices_list
0106      * otherwise.
0107      */
0108     list = from ? &from->list : &omapdss_devices_list;
0109 
0110     list_for_each_entry(dssdev, list, list) {
0111         /*
0112          * Stop if we reach the omapdss_devices_list, that's the end of
0113          * the list.
0114          */
0115         if (&dssdev->list == &omapdss_devices_list) {
0116             dssdev = NULL;
0117             goto done;
0118         }
0119 
0120         if (dssdev->id && dssdev->bridge)
0121             goto done;
0122     }
0123 
0124     dssdev = NULL;
0125 
0126 done:
0127     if (from)
0128         omapdss_device_put(from);
0129     if (dssdev)
0130         omapdss_device_get(dssdev);
0131 
0132     mutex_unlock(&omapdss_devices_lock);
0133     return dssdev;
0134 }
0135 
0136 static bool omapdss_device_is_connected(struct omap_dss_device *dssdev)
0137 {
0138     return dssdev->dss;
0139 }
0140 
0141 int omapdss_device_connect(struct dss_device *dss,
0142                struct omap_dss_device *src,
0143                struct omap_dss_device *dst)
0144 {
0145     dev_dbg(&dss->pdev->dev, "connect(%s, %s)\n",
0146         src ? dev_name(src->dev) : "NULL",
0147         dst ? dev_name(dst->dev) : "NULL");
0148 
0149     if (!dst) {
0150         /*
0151          * The destination is NULL when the source is connected to a
0152          * bridge instead of a DSS device. Stop here, we will attach
0153          * the bridge later when we will have a DRM encoder.
0154          */
0155         return src && src->bridge ? 0 : -EINVAL;
0156     }
0157 
0158     if (omapdss_device_is_connected(dst))
0159         return -EBUSY;
0160 
0161     dst->dss = dss;
0162 
0163     return 0;
0164 }
0165 
0166 void omapdss_device_disconnect(struct omap_dss_device *src,
0167                    struct omap_dss_device *dst)
0168 {
0169     struct dss_device *dss = src ? src->dss : dst->dss;
0170 
0171     dev_dbg(&dss->pdev->dev, "disconnect(%s, %s)\n",
0172         src ? dev_name(src->dev) : "NULL",
0173         dst ? dev_name(dst->dev) : "NULL");
0174 
0175     if (!dst) {
0176         WARN_ON(!src->bridge);
0177         return;
0178     }
0179 
0180     if (!dst->id && !omapdss_device_is_connected(dst)) {
0181         WARN_ON(1);
0182         return;
0183     }
0184 
0185     dst->dss = NULL;
0186 }
0187 
0188 /* -----------------------------------------------------------------------------
0189  * Components Handling
0190  */
0191 
0192 static struct list_head omapdss_comp_list;
0193 
0194 struct omapdss_comp_node {
0195     struct list_head list;
0196     struct device_node *node;
0197     bool dss_core_component;
0198     const char *compat;
0199 };
0200 
0201 static bool omapdss_list_contains(const struct device_node *node)
0202 {
0203     struct omapdss_comp_node *comp;
0204 
0205     list_for_each_entry(comp, &omapdss_comp_list, list) {
0206         if (comp->node == node)
0207             return true;
0208     }
0209 
0210     return false;
0211 }
0212 
0213 static void omapdss_walk_device(struct device *dev, struct device_node *node,
0214                 bool dss_core)
0215 {
0216     struct omapdss_comp_node *comp;
0217     struct device_node *n;
0218     const char *compat;
0219     int ret;
0220 
0221     ret = of_property_read_string(node, "compatible", &compat);
0222     if (ret < 0)
0223         return;
0224 
0225     comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
0226     if (comp) {
0227         comp->node = node;
0228         comp->dss_core_component = dss_core;
0229         comp->compat = compat;
0230         list_add(&comp->list, &omapdss_comp_list);
0231     }
0232 
0233     /*
0234      * of_graph_get_remote_port_parent() prints an error if there is no
0235      * port/ports node. To avoid that, check first that there's the node.
0236      */
0237     n = of_get_child_by_name(node, "ports");
0238     if (!n)
0239         n = of_get_child_by_name(node, "port");
0240     if (!n)
0241         return;
0242 
0243     of_node_put(n);
0244 
0245     n = NULL;
0246     while ((n = of_graph_get_next_endpoint(node, n)) != NULL) {
0247         struct device_node *pn = of_graph_get_remote_port_parent(n);
0248 
0249         if (!pn)
0250             continue;
0251 
0252         if (!of_device_is_available(pn) || omapdss_list_contains(pn)) {
0253             of_node_put(pn);
0254             continue;
0255         }
0256 
0257         omapdss_walk_device(dev, pn, false);
0258     }
0259 }
0260 
0261 void omapdss_gather_components(struct device *dev)
0262 {
0263     struct device_node *child;
0264 
0265     INIT_LIST_HEAD(&omapdss_comp_list);
0266 
0267     omapdss_walk_device(dev, dev->of_node, true);
0268 
0269     for_each_available_child_of_node(dev->of_node, child)
0270         omapdss_walk_device(dev, child, true);
0271 }
0272 
0273 static bool omapdss_component_is_loaded(struct omapdss_comp_node *comp)
0274 {
0275     if (comp->dss_core_component)
0276         return true;
0277     if (!strstarts(comp->compat, "omapdss,"))
0278         return true;
0279     if (omapdss_device_is_registered(comp->node))
0280         return true;
0281 
0282     return false;
0283 }
0284 
0285 bool omapdss_stack_is_ready(void)
0286 {
0287     struct omapdss_comp_node *comp;
0288 
0289     list_for_each_entry(comp, &omapdss_comp_list, list) {
0290         if (!omapdss_component_is_loaded(comp))
0291             return false;
0292     }
0293 
0294     return true;
0295 }