1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ 4 * Author: Archit Taneja <archit@ti.com> 5 */ 6 7 #include <linux/kernel.h> 8 #include <linux/module.h> 9 #include <linux/platform_device.h> 10 #include <linux/slab.h> 11 #include <linux/of.h> 12 #include <linux/of_graph.h> 13 14 #include <drm/drm_bridge.h> 15 #include <drm/drm_panel.h> 16 17 #include "dss.h" 18 #include "omapdss.h" 19 20 int omapdss_device_init_output(struct omap_dss_device *out) 21 { 22 struct device_node *remote_node; 23 24 remote_node = of_graph_get_remote_node(out->dev->of_node, 0, 0); 25 if (!remote_node) { 26 dev_dbg(out->dev, "failed to find video sink\n"); 27 return 0; 28 } 29 30 out->next = omapdss_find_device_by_node(remote_node); 31 out->bridge = of_drm_find_bridge(remote_node); 32 out->panel = of_drm_find_panel(remote_node); 33 if (IS_ERR(out->panel)) 34 out->panel = NULL; 35 36 of_node_put(remote_node); 37 38 if (out->next && out->type != out->next->type) { 39 dev_err(out->dev, "output type and display type don't match\n"); 40 omapdss_device_put(out->next); 41 out->next = NULL; 42 return -EINVAL; 43 } 44 45 return out->next || out->bridge || out->panel ? 0 : -EPROBE_DEFER; 46 } 47 EXPORT_SYMBOL(omapdss_device_init_output); 48 49 void omapdss_device_cleanup_output(struct omap_dss_device *out) 50 { 51 if (out->next) 52 omapdss_device_put(out->next); 53 } 54 EXPORT_SYMBOL(omapdss_device_cleanup_output); 55 56 int dss_install_mgr_ops(struct dss_device *dss, 57 const struct dss_mgr_ops *mgr_ops, 58 struct omap_drm_private *priv) 59 { 60 if (dss->mgr_ops) 61 return -EBUSY; 62 63 dss->mgr_ops = mgr_ops; 64 dss->mgr_ops_priv = priv; 65 66 return 0; 67 } 68 EXPORT_SYMBOL(dss_install_mgr_ops); 69 70 void dss_uninstall_mgr_ops(struct dss_device *dss) 71 { 72 dss->mgr_ops = NULL; 73 dss->mgr_ops_priv = NULL; 74 } 75 EXPORT_SYMBOL(dss_uninstall_mgr_ops); 76 77 void dss_mgr_set_timings(struct omap_dss_device *dssdev, 78 const struct videomode *vm) 79 { 80 dssdev->dss->mgr_ops->set_timings(dssdev->dss->mgr_ops_priv, 81 dssdev->dispc_channel, vm); 82 } 83 EXPORT_SYMBOL(dss_mgr_set_timings); 84 85 void dss_mgr_set_lcd_config(struct omap_dss_device *dssdev, 86 const struct dss_lcd_mgr_config *config) 87 { 88 dssdev->dss->mgr_ops->set_lcd_config(dssdev->dss->mgr_ops_priv, 89 dssdev->dispc_channel, config); 90 } 91 EXPORT_SYMBOL(dss_mgr_set_lcd_config); 92 93 int dss_mgr_enable(struct omap_dss_device *dssdev) 94 { 95 return dssdev->dss->mgr_ops->enable(dssdev->dss->mgr_ops_priv, 96 dssdev->dispc_channel); 97 } 98 EXPORT_SYMBOL(dss_mgr_enable); 99 100 void dss_mgr_disable(struct omap_dss_device *dssdev) 101 { 102 dssdev->dss->mgr_ops->disable(dssdev->dss->mgr_ops_priv, 103 dssdev->dispc_channel); 104 } 105 EXPORT_SYMBOL(dss_mgr_disable); 106 107 void dss_mgr_start_update(struct omap_dss_device *dssdev) 108 { 109 dssdev->dss->mgr_ops->start_update(dssdev->dss->mgr_ops_priv, 110 dssdev->dispc_channel); 111 } 112 EXPORT_SYMBOL(dss_mgr_start_update); 113 114 int dss_mgr_register_framedone_handler(struct omap_dss_device *dssdev, 115 void (*handler)(void *), void *data) 116 { 117 struct dss_device *dss = dssdev->dss; 118 119 return dss->mgr_ops->register_framedone_handler(dss->mgr_ops_priv, 120 dssdev->dispc_channel, 121 handler, data); 122 } 123 EXPORT_SYMBOL(dss_mgr_register_framedone_handler); 124 125 void dss_mgr_unregister_framedone_handler(struct omap_dss_device *dssdev, 126 void (*handler)(void *), void *data) 127 { 128 struct dss_device *dss = dssdev->dss; 129 130 dss->mgr_ops->unregister_framedone_handler(dss->mgr_ops_priv, 131 dssdev->dispc_channel, 132 handler, data); 133 } 134 EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler); 135