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 struct drm_bridge *local_bridge) 22 { 23 struct device_node *remote_node; 24 int ret; 25 26 remote_node = of_graph_get_remote_node(out->dev->of_node, 27 out->of_port, 0); 28 if (!remote_node) { 29 dev_dbg(out->dev, "failed to find video sink\n"); 30 return 0; 31 } 32 33 out->next = omapdss_find_device_by_node(remote_node); 34 out->bridge = of_drm_find_bridge(remote_node); 35 out->panel = of_drm_find_panel(remote_node); 36 if (IS_ERR(out->panel)) 37 out->panel = NULL; 38 39 of_node_put(remote_node); 40 41 if (out->next && out->type != out->next->type) { 42 dev_err(out->dev, "output type and display type don't match\n"); 43 ret = -EINVAL; 44 goto error; 45 } 46 47 if (out->panel) { 48 struct drm_bridge *bridge; 49 50 bridge = drm_panel_bridge_add(out->panel); 51 if (IS_ERR(bridge)) { 52 dev_err(out->dev, 53 "unable to create panel bridge (%ld)\n", 54 PTR_ERR(bridge)); 55 ret = PTR_ERR(bridge); 56 goto error; 57 } 58 59 out->bridge = bridge; 60 } 61 62 if (local_bridge) { 63 if (!out->bridge) { 64 ret = -EPROBE_DEFER; 65 goto error; 66 } 67 68 out->next_bridge = out->bridge; 69 out->bridge = local_bridge; 70 } 71 72 if (!out->next && !out->bridge) { 73 ret = -EPROBE_DEFER; 74 goto error; 75 } 76 77 return 0; 78 79 error: 80 omapdss_device_cleanup_output(out); 81 out->next = NULL; 82 return ret; 83 } 84 EXPORT_SYMBOL(omapdss_device_init_output); 85 86 void omapdss_device_cleanup_output(struct omap_dss_device *out) 87 { 88 if (out->bridge && out->panel) 89 drm_panel_bridge_remove(out->next_bridge ? 90 out->next_bridge : out->bridge); 91 92 if (out->next) 93 omapdss_device_put(out->next); 94 } 95 EXPORT_SYMBOL(omapdss_device_cleanup_output); 96 97 int dss_install_mgr_ops(struct dss_device *dss, 98 const struct dss_mgr_ops *mgr_ops, 99 struct omap_drm_private *priv) 100 { 101 if (dss->mgr_ops) 102 return -EBUSY; 103 104 dss->mgr_ops = mgr_ops; 105 dss->mgr_ops_priv = priv; 106 107 return 0; 108 } 109 EXPORT_SYMBOL(dss_install_mgr_ops); 110 111 void dss_uninstall_mgr_ops(struct dss_device *dss) 112 { 113 dss->mgr_ops = NULL; 114 dss->mgr_ops_priv = NULL; 115 } 116 EXPORT_SYMBOL(dss_uninstall_mgr_ops); 117 118 void dss_mgr_set_timings(struct omap_dss_device *dssdev, 119 const struct videomode *vm) 120 { 121 dssdev->dss->mgr_ops->set_timings(dssdev->dss->mgr_ops_priv, 122 dssdev->dispc_channel, vm); 123 } 124 EXPORT_SYMBOL(dss_mgr_set_timings); 125 126 void dss_mgr_set_lcd_config(struct omap_dss_device *dssdev, 127 const struct dss_lcd_mgr_config *config) 128 { 129 dssdev->dss->mgr_ops->set_lcd_config(dssdev->dss->mgr_ops_priv, 130 dssdev->dispc_channel, config); 131 } 132 EXPORT_SYMBOL(dss_mgr_set_lcd_config); 133 134 int dss_mgr_enable(struct omap_dss_device *dssdev) 135 { 136 return dssdev->dss->mgr_ops->enable(dssdev->dss->mgr_ops_priv, 137 dssdev->dispc_channel); 138 } 139 EXPORT_SYMBOL(dss_mgr_enable); 140 141 void dss_mgr_disable(struct omap_dss_device *dssdev) 142 { 143 dssdev->dss->mgr_ops->disable(dssdev->dss->mgr_ops_priv, 144 dssdev->dispc_channel); 145 } 146 EXPORT_SYMBOL(dss_mgr_disable); 147 148 void dss_mgr_start_update(struct omap_dss_device *dssdev) 149 { 150 dssdev->dss->mgr_ops->start_update(dssdev->dss->mgr_ops_priv, 151 dssdev->dispc_channel); 152 } 153 EXPORT_SYMBOL(dss_mgr_start_update); 154 155 int dss_mgr_register_framedone_handler(struct omap_dss_device *dssdev, 156 void (*handler)(void *), void *data) 157 { 158 struct dss_device *dss = dssdev->dss; 159 160 return dss->mgr_ops->register_framedone_handler(dss->mgr_ops_priv, 161 dssdev->dispc_channel, 162 handler, data); 163 } 164 EXPORT_SYMBOL(dss_mgr_register_framedone_handler); 165 166 void dss_mgr_unregister_framedone_handler(struct omap_dss_device *dssdev, 167 void (*handler)(void *), void *data) 168 { 169 struct dss_device *dss = dssdev->dss; 170 171 dss->mgr_ops->unregister_framedone_handler(dss->mgr_ops_priv, 172 dssdev->dispc_channel, 173 handler, data); 174 } 175 EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler); 176