1 /* 2 * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ 3 * Author: Archit Taneja <archit@ti.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 as published by 7 * the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include <linux/kernel.h> 19 #include <linux/module.h> 20 #include <linux/platform_device.h> 21 #include <linux/slab.h> 22 #include <linux/of.h> 23 24 #include "omapdss.h" 25 26 static LIST_HEAD(output_list); 27 static DEFINE_MUTEX(output_lock); 28 29 int omapdss_output_set_device(struct omap_dss_device *out, 30 struct omap_dss_device *dssdev) 31 { 32 int r; 33 34 mutex_lock(&output_lock); 35 36 if (out->dst) { 37 dev_err(out->dev, 38 "output already has device %s connected to it\n", 39 out->dst->name); 40 r = -EINVAL; 41 goto err; 42 } 43 44 if (out->output_type != dssdev->type) { 45 dev_err(out->dev, "output type and display type don't match\n"); 46 r = -EINVAL; 47 goto err; 48 } 49 50 out->dst = dssdev; 51 dssdev->src = out; 52 53 mutex_unlock(&output_lock); 54 55 return 0; 56 err: 57 mutex_unlock(&output_lock); 58 59 return r; 60 } 61 EXPORT_SYMBOL(omapdss_output_set_device); 62 63 int omapdss_output_unset_device(struct omap_dss_device *out) 64 { 65 int r; 66 67 mutex_lock(&output_lock); 68 69 if (!out->dst) { 70 dev_err(out->dev, 71 "output doesn't have a device connected to it\n"); 72 r = -EINVAL; 73 goto err; 74 } 75 76 if (out->dst->state != OMAP_DSS_DISPLAY_DISABLED) { 77 dev_err(out->dev, 78 "device %s is not disabled, cannot unset device\n", 79 out->dst->name); 80 r = -EINVAL; 81 goto err; 82 } 83 84 out->dst->src = NULL; 85 out->dst = NULL; 86 87 mutex_unlock(&output_lock); 88 89 return 0; 90 err: 91 mutex_unlock(&output_lock); 92 93 return r; 94 } 95 EXPORT_SYMBOL(omapdss_output_unset_device); 96 97 int omapdss_register_output(struct omap_dss_device *out) 98 { 99 list_add_tail(&out->list, &output_list); 100 return 0; 101 } 102 EXPORT_SYMBOL(omapdss_register_output); 103 104 void omapdss_unregister_output(struct omap_dss_device *out) 105 { 106 list_del(&out->list); 107 } 108 EXPORT_SYMBOL(omapdss_unregister_output); 109 110 bool omapdss_component_is_output(struct device_node *node) 111 { 112 struct omap_dss_device *out; 113 114 list_for_each_entry(out, &output_list, list) { 115 if (out->dev->of_node == node) 116 return true; 117 } 118 119 return false; 120 } 121 EXPORT_SYMBOL(omapdss_component_is_output); 122 123 struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id) 124 { 125 struct omap_dss_device *out; 126 127 list_for_each_entry(out, &output_list, list) { 128 if (out->id == id) 129 return out; 130 } 131 132 return NULL; 133 } 134 EXPORT_SYMBOL(omap_dss_get_output); 135 136 struct omap_dss_device *omap_dss_find_output_by_port_node(struct device_node *port) 137 { 138 struct device_node *src_node; 139 struct omap_dss_device *out; 140 u32 reg; 141 142 src_node = dss_of_port_get_parent_device(port); 143 if (!src_node) 144 return NULL; 145 146 reg = dss_of_port_get_port_number(port); 147 148 list_for_each_entry(out, &output_list, list) { 149 if (out->dev->of_node == src_node && out->port_num == reg) { 150 of_node_put(src_node); 151 return omap_dss_get_device(out); 152 } 153 } 154 155 of_node_put(src_node); 156 157 return NULL; 158 } 159 160 struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev) 161 { 162 while (dssdev->src) 163 dssdev = dssdev->src; 164 165 if (dssdev->id != 0) 166 return omap_dss_get_device(dssdev); 167 168 return NULL; 169 } 170 EXPORT_SYMBOL(omapdss_find_output_from_display); 171 172 static const struct dss_mgr_ops *dss_mgr_ops; 173 static struct omap_drm_private *dss_mgr_ops_priv; 174 175 int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops, 176 struct omap_drm_private *priv) 177 { 178 if (dss_mgr_ops) 179 return -EBUSY; 180 181 dss_mgr_ops = mgr_ops; 182 dss_mgr_ops_priv = priv; 183 184 return 0; 185 } 186 EXPORT_SYMBOL(dss_install_mgr_ops); 187 188 void dss_uninstall_mgr_ops(void) 189 { 190 dss_mgr_ops = NULL; 191 dss_mgr_ops_priv = NULL; 192 } 193 EXPORT_SYMBOL(dss_uninstall_mgr_ops); 194 195 int dss_mgr_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst) 196 { 197 return dss_mgr_ops->connect(dss_mgr_ops_priv, 198 dssdev->dispc_channel, dst); 199 } 200 EXPORT_SYMBOL(dss_mgr_connect); 201 202 void dss_mgr_disconnect(struct omap_dss_device *dssdev, 203 struct omap_dss_device *dst) 204 { 205 dss_mgr_ops->disconnect(dss_mgr_ops_priv, dssdev->dispc_channel, dst); 206 } 207 EXPORT_SYMBOL(dss_mgr_disconnect); 208 209 void dss_mgr_set_timings(struct omap_dss_device *dssdev, 210 const struct videomode *vm) 211 { 212 dss_mgr_ops->set_timings(dss_mgr_ops_priv, dssdev->dispc_channel, vm); 213 } 214 EXPORT_SYMBOL(dss_mgr_set_timings); 215 216 void dss_mgr_set_lcd_config(struct omap_dss_device *dssdev, 217 const struct dss_lcd_mgr_config *config) 218 { 219 dss_mgr_ops->set_lcd_config(dss_mgr_ops_priv, 220 dssdev->dispc_channel, config); 221 } 222 EXPORT_SYMBOL(dss_mgr_set_lcd_config); 223 224 int dss_mgr_enable(struct omap_dss_device *dssdev) 225 { 226 return dss_mgr_ops->enable(dss_mgr_ops_priv, dssdev->dispc_channel); 227 } 228 EXPORT_SYMBOL(dss_mgr_enable); 229 230 void dss_mgr_disable(struct omap_dss_device *dssdev) 231 { 232 dss_mgr_ops->disable(dss_mgr_ops_priv, dssdev->dispc_channel); 233 } 234 EXPORT_SYMBOL(dss_mgr_disable); 235 236 void dss_mgr_start_update(struct omap_dss_device *dssdev) 237 { 238 dss_mgr_ops->start_update(dss_mgr_ops_priv, dssdev->dispc_channel); 239 } 240 EXPORT_SYMBOL(dss_mgr_start_update); 241 242 int dss_mgr_register_framedone_handler(struct omap_dss_device *dssdev, 243 void (*handler)(void *), void *data) 244 { 245 return dss_mgr_ops->register_framedone_handler(dss_mgr_ops_priv, 246 dssdev->dispc_channel, 247 handler, data); 248 } 249 EXPORT_SYMBOL(dss_mgr_register_framedone_handler); 250 251 void dss_mgr_unregister_framedone_handler(struct omap_dss_device *dssdev, 252 void (*handler)(void *), void *data) 253 { 254 dss_mgr_ops->unregister_framedone_handler(dss_mgr_ops_priv, 255 dssdev->dispc_channel, 256 handler, data); 257 } 258 EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler); 259