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
omapdss_output_set_device(struct omap_dss_device * out,struct omap_dss_device * dssdev)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
omapdss_output_unset_device(struct omap_dss_device * out)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
omapdss_register_output(struct omap_dss_device * out)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
omapdss_unregister_output(struct omap_dss_device * out)93 void omapdss_unregister_output(struct omap_dss_device *out)
94 {
95 list_del(&out->list);
96 }
97 EXPORT_SYMBOL(omapdss_unregister_output);
98
omap_dss_get_output(enum omap_dss_output_id id)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
omap_dss_find_output(const char * name)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
omap_dss_find_output_by_port_node(struct device_node * port)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
omapdss_find_output_from_display(struct omap_dss_device * dssdev)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
omapdss_find_mgr_from_display(struct omap_dss_device * dssdev)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
dss_install_mgr_ops(const struct dss_mgr_ops * mgr_ops)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
dss_uninstall_mgr_ops(void)193 void dss_uninstall_mgr_ops(void)
194 {
195 dss_mgr_ops = NULL;
196 }
197 EXPORT_SYMBOL(dss_uninstall_mgr_ops);
198
dss_mgr_connect(struct omap_overlay_manager * mgr,struct omap_dss_device * dst)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
dss_mgr_disconnect(struct omap_overlay_manager * mgr,struct omap_dss_device * dst)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
dss_mgr_set_timings(struct omap_overlay_manager * mgr,const struct omap_video_timings * timings)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
dss_mgr_set_lcd_config(struct omap_overlay_manager * mgr,const struct dss_lcd_mgr_config * config)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
dss_mgr_enable(struct omap_overlay_manager * mgr)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
dss_mgr_disable(struct omap_overlay_manager * mgr)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
dss_mgr_start_update(struct omap_overlay_manager * mgr)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
dss_mgr_register_framedone_handler(struct omap_overlay_manager * mgr,void (* handler)(void *),void * data)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
dss_mgr_unregister_framedone_handler(struct omap_overlay_manager * mgr,void (* handler)(void *),void * data)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