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