xref: /linux/drivers/video/fbdev/omap2/omapfb/dss/output.c (revision 6e9a12f85a7567bb9a41d5230468886bd6a27b20)
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