1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2012 Texas Instruments Ltd 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 13 #include <video/omapfb_dss.h> 14 15 #include "dss.h" 16 17 static LIST_HEAD(output_list); 18 static DEFINE_MUTEX(output_lock); 19 20 int omapdss_output_set_device(struct omap_dss_device *out, 21 struct omap_dss_device *dssdev) 22 { 23 int r; 24 25 mutex_lock(&output_lock); 26 27 if (out->dst) { 28 DSSERR("output already has device %s connected to it\n", 29 out->dst->name); 30 r = -EINVAL; 31 goto err; 32 } 33 34 if (out->output_type != dssdev->type) { 35 DSSERR("output type and display type don't match\n"); 36 r = -EINVAL; 37 goto err; 38 } 39 40 out->dst = dssdev; 41 dssdev->src = out; 42 43 mutex_unlock(&output_lock); 44 45 return 0; 46 err: 47 mutex_unlock(&output_lock); 48 49 return r; 50 } 51 EXPORT_SYMBOL(omapdss_output_set_device); 52 53 int omapdss_output_unset_device(struct omap_dss_device *out) 54 { 55 int r; 56 57 mutex_lock(&output_lock); 58 59 if (!out->dst) { 60 DSSERR("output doesn't have a device connected to it\n"); 61 r = -EINVAL; 62 goto err; 63 } 64 65 if (out->dst->state != OMAP_DSS_DISPLAY_DISABLED) { 66 DSSERR("device %s is not disabled, cannot unset device\n", 67 out->dst->name); 68 r = -EINVAL; 69 goto err; 70 } 71 72 out->dst->src = NULL; 73 out->dst = NULL; 74 75 mutex_unlock(&output_lock); 76 77 return 0; 78 err: 79 mutex_unlock(&output_lock); 80 81 return r; 82 } 83 EXPORT_SYMBOL(omapdss_output_unset_device); 84 85 int omapdss_register_output(struct omap_dss_device *out) 86 { 87 list_add_tail(&out->list, &output_list); 88 return 0; 89 } 90 EXPORT_SYMBOL(omapdss_register_output); 91 92 void omapdss_unregister_output(struct omap_dss_device *out) 93 { 94 list_del(&out->list); 95 } 96 EXPORT_SYMBOL(omapdss_unregister_output); 97 98 struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id) 99 { 100 struct omap_dss_device *out; 101 102 list_for_each_entry(out, &output_list, list) { 103 if (out->id == id) 104 return out; 105 } 106 107 return NULL; 108 } 109 EXPORT_SYMBOL(omap_dss_get_output); 110 111 struct omap_dss_device *omap_dss_find_output(const char *name) 112 { 113 struct omap_dss_device *out; 114 115 list_for_each_entry(out, &output_list, list) { 116 if (strcmp(out->name, name) == 0) 117 return omap_dss_get_device(out); 118 } 119 120 return NULL; 121 } 122 EXPORT_SYMBOL(omap_dss_find_output); 123 124 struct omap_dss_device *omap_dss_find_output_by_port_node(struct device_node *port) 125 { 126 struct device_node *src_node; 127 struct omap_dss_device *out; 128 u32 reg; 129 130 src_node = dss_of_port_get_parent_device(port); 131 if (!src_node) 132 return NULL; 133 134 reg = dss_of_port_get_port_number(port); 135 136 list_for_each_entry(out, &output_list, list) { 137 if (out->dev->of_node == src_node && out->port_num == reg) { 138 of_node_put(src_node); 139 return omap_dss_get_device(out); 140 } 141 } 142 143 of_node_put(src_node); 144 145 return NULL; 146 } 147 EXPORT_SYMBOL(omap_dss_find_output_by_port_node); 148 149 struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev) 150 { 151 while (dssdev->src) 152 dssdev = dssdev->src; 153 154 if (dssdev->id != 0) 155 return omap_dss_get_device(dssdev); 156 157 return NULL; 158 } 159 EXPORT_SYMBOL(omapdss_find_output_from_display); 160 161 struct omap_overlay_manager *omapdss_find_mgr_from_display(struct omap_dss_device *dssdev) 162 { 163 struct omap_dss_device *out; 164 struct omap_overlay_manager *mgr; 165 166 out = omapdss_find_output_from_display(dssdev); 167 168 if (out == NULL) 169 return NULL; 170 171 mgr = out->manager; 172 173 omap_dss_put_device(out); 174 175 return mgr; 176 } 177 EXPORT_SYMBOL(omapdss_find_mgr_from_display); 178 179 static const struct dss_mgr_ops *dss_mgr_ops; 180 181 int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops) 182 { 183 if (dss_mgr_ops) 184 return -EBUSY; 185 186 dss_mgr_ops = mgr_ops; 187 188 return 0; 189 } 190 EXPORT_SYMBOL(dss_install_mgr_ops); 191 192 void dss_uninstall_mgr_ops(void) 193 { 194 dss_mgr_ops = NULL; 195 } 196 EXPORT_SYMBOL(dss_uninstall_mgr_ops); 197 198 int dss_mgr_connect(struct omap_overlay_manager *mgr, 199 struct omap_dss_device *dst) 200 { 201 return dss_mgr_ops->connect(mgr, dst); 202 } 203 EXPORT_SYMBOL(dss_mgr_connect); 204 205 void dss_mgr_disconnect(struct omap_overlay_manager *mgr, 206 struct omap_dss_device *dst) 207 { 208 dss_mgr_ops->disconnect(mgr, dst); 209 } 210 EXPORT_SYMBOL(dss_mgr_disconnect); 211 212 void dss_mgr_set_timings(struct omap_overlay_manager *mgr, 213 const struct omap_video_timings *timings) 214 { 215 dss_mgr_ops->set_timings(mgr, timings); 216 } 217 EXPORT_SYMBOL(dss_mgr_set_timings); 218 219 void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, 220 const struct dss_lcd_mgr_config *config) 221 { 222 dss_mgr_ops->set_lcd_config(mgr, config); 223 } 224 EXPORT_SYMBOL(dss_mgr_set_lcd_config); 225 226 int dss_mgr_enable(struct omap_overlay_manager *mgr) 227 { 228 return dss_mgr_ops->enable(mgr); 229 } 230 EXPORT_SYMBOL(dss_mgr_enable); 231 232 void dss_mgr_disable(struct omap_overlay_manager *mgr) 233 { 234 dss_mgr_ops->disable(mgr); 235 } 236 EXPORT_SYMBOL(dss_mgr_disable); 237 238 void dss_mgr_start_update(struct omap_overlay_manager *mgr) 239 { 240 dss_mgr_ops->start_update(mgr); 241 } 242 EXPORT_SYMBOL(dss_mgr_start_update); 243 244 int dss_mgr_register_framedone_handler(struct omap_overlay_manager *mgr, 245 void (*handler)(void *), void *data) 246 { 247 return dss_mgr_ops->register_framedone_handler(mgr, handler, data); 248 } 249 EXPORT_SYMBOL(dss_mgr_register_framedone_handler); 250 251 void dss_mgr_unregister_framedone_handler(struct omap_overlay_manager *mgr, 252 void (*handler)(void *), void *data) 253 { 254 dss_mgr_ops->unregister_framedone_handler(mgr, handler, data); 255 } 256 EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler); 257