1 /*
2  * Copyright (C) 2009 Nokia Corporation
3  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
4  *
5  * Some code and ideas taken from drivers/video/omap/ driver
6  * by Imre Deak.
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License version 2 as published by
10  * the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along with
18  * this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #define DSS_SUBSYS_NAME "MANAGER"
22 
23 #include <linux/kernel.h>
24 #include <linux/slab.h>
25 #include <linux/module.h>
26 #include <linux/platform_device.h>
27 #include <linux/jiffies.h>
28 
29 #include <video/omapfb_dss.h>
30 
31 #include "dss.h"
32 #include "dss_features.h"
33 
34 static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
35 {
36 	return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
37 }
38 
39 static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
40 {
41 	struct omap_dss_device *dssdev = mgr->get_device(mgr);
42 
43 	return snprintf(buf, PAGE_SIZE, "%s\n", dssdev ?
44 			dssdev->name : "<none>");
45 }
46 
47 static int manager_display_match(struct omap_dss_device *dssdev, void *data)
48 {
49 	const char *str = data;
50 
51 	return sysfs_streq(dssdev->name, str);
52 }
53 
54 static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
55 		const char *buf, size_t size)
56 {
57 	int r = 0;
58 	size_t len = size;
59 	struct omap_dss_device *dssdev = NULL;
60 	struct omap_dss_device *old_dssdev;
61 
62 	if (buf[size-1] == '\n')
63 		--len;
64 
65 	if (len > 0)
66 		dssdev = omap_dss_find_device((void *)buf,
67 			manager_display_match);
68 
69 	if (len > 0 && dssdev == NULL)
70 		return -EINVAL;
71 
72 	if (dssdev) {
73 		DSSDBG("display %s found\n", dssdev->name);
74 
75 		if (omapdss_device_is_connected(dssdev)) {
76 			DSSERR("new display is already connected\n");
77 			r = -EINVAL;
78 			goto put_device;
79 		}
80 
81 		if (omapdss_device_is_enabled(dssdev)) {
82 			DSSERR("new display is not disabled\n");
83 			r = -EINVAL;
84 			goto put_device;
85 		}
86 	}
87 
88 	old_dssdev = mgr->get_device(mgr);
89 	if (old_dssdev) {
90 		if (omapdss_device_is_enabled(old_dssdev)) {
91 			DSSERR("old display is not disabled\n");
92 			r = -EINVAL;
93 			goto put_device;
94 		}
95 
96 		old_dssdev->driver->disconnect(old_dssdev);
97 	}
98 
99 	if (dssdev) {
100 		r = dssdev->driver->connect(dssdev);
101 		if (r) {
102 			DSSERR("failed to connect new device\n");
103 			goto put_device;
104 		}
105 
106 		old_dssdev = mgr->get_device(mgr);
107 		if (old_dssdev != dssdev) {
108 			DSSERR("failed to connect device to this manager\n");
109 			dssdev->driver->disconnect(dssdev);
110 			goto put_device;
111 		}
112 
113 		r = mgr->apply(mgr);
114 		if (r) {
115 			DSSERR("failed to apply dispc config\n");
116 			goto put_device;
117 		}
118 	}
119 
120 put_device:
121 	if (dssdev)
122 		omap_dss_put_device(dssdev);
123 
124 	return r ? r : size;
125 }
126 
127 static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
128 					  char *buf)
129 {
130 	struct omap_overlay_manager_info info;
131 
132 	mgr->get_manager_info(mgr, &info);
133 
134 	return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color);
135 }
136 
137 static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
138 					   const char *buf, size_t size)
139 {
140 	struct omap_overlay_manager_info info;
141 	u32 color;
142 	int r;
143 
144 	r = kstrtouint(buf, 0, &color);
145 	if (r)
146 		return r;
147 
148 	mgr->get_manager_info(mgr, &info);
149 
150 	info.default_color = color;
151 
152 	r = mgr->set_manager_info(mgr, &info);
153 	if (r)
154 		return r;
155 
156 	r = mgr->apply(mgr);
157 	if (r)
158 		return r;
159 
160 	return size;
161 }
162 
163 static const char *trans_key_type_str[] = {
164 	"gfx-destination",
165 	"video-source",
166 };
167 
168 static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
169 					   char *buf)
170 {
171 	enum omap_dss_trans_key_type key_type;
172 	struct omap_overlay_manager_info info;
173 
174 	mgr->get_manager_info(mgr, &info);
175 
176 	key_type = info.trans_key_type;
177 	BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
178 
179 	return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
180 }
181 
182 static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
183 					    const char *buf, size_t size)
184 {
185 	struct omap_overlay_manager_info info;
186 	int r;
187 
188 	r = sysfs_match_string(trans_key_type_str, buf);
189 	if (r < 0)
190 		return r;
191 
192 	mgr->get_manager_info(mgr, &info);
193 
194 	info.trans_key_type = r;
195 
196 	r = mgr->set_manager_info(mgr, &info);
197 	if (r)
198 		return r;
199 
200 	r = mgr->apply(mgr);
201 	if (r)
202 		return r;
203 
204 	return size;
205 }
206 
207 static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
208 					    char *buf)
209 {
210 	struct omap_overlay_manager_info info;
211 
212 	mgr->get_manager_info(mgr, &info);
213 
214 	return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key);
215 }
216 
217 static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
218 					     const char *buf, size_t size)
219 {
220 	struct omap_overlay_manager_info info;
221 	u32 key_value;
222 	int r;
223 
224 	r = kstrtouint(buf, 0, &key_value);
225 	if (r)
226 		return r;
227 
228 	mgr->get_manager_info(mgr, &info);
229 
230 	info.trans_key = key_value;
231 
232 	r = mgr->set_manager_info(mgr, &info);
233 	if (r)
234 		return r;
235 
236 	r = mgr->apply(mgr);
237 	if (r)
238 		return r;
239 
240 	return size;
241 }
242 
243 static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
244 					      char *buf)
245 {
246 	struct omap_overlay_manager_info info;
247 
248 	mgr->get_manager_info(mgr, &info);
249 
250 	return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled);
251 }
252 
253 static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
254 					       const char *buf, size_t size)
255 {
256 	struct omap_overlay_manager_info info;
257 	bool enable;
258 	int r;
259 
260 	r = strtobool(buf, &enable);
261 	if (r)
262 		return r;
263 
264 	mgr->get_manager_info(mgr, &info);
265 
266 	info.trans_enabled = enable;
267 
268 	r = mgr->set_manager_info(mgr, &info);
269 	if (r)
270 		return r;
271 
272 	r = mgr->apply(mgr);
273 	if (r)
274 		return r;
275 
276 	return size;
277 }
278 
279 static ssize_t manager_alpha_blending_enabled_show(
280 		struct omap_overlay_manager *mgr, char *buf)
281 {
282 	struct omap_overlay_manager_info info;
283 
284 	if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
285 		return -ENODEV;
286 
287 	mgr->get_manager_info(mgr, &info);
288 
289 	return snprintf(buf, PAGE_SIZE, "%d\n",
290 		info.partial_alpha_enabled);
291 }
292 
293 static ssize_t manager_alpha_blending_enabled_store(
294 		struct omap_overlay_manager *mgr,
295 		const char *buf, size_t size)
296 {
297 	struct omap_overlay_manager_info info;
298 	bool enable;
299 	int r;
300 
301 	if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
302 		return -ENODEV;
303 
304 	r = strtobool(buf, &enable);
305 	if (r)
306 		return r;
307 
308 	mgr->get_manager_info(mgr, &info);
309 
310 	info.partial_alpha_enabled = enable;
311 
312 	r = mgr->set_manager_info(mgr, &info);
313 	if (r)
314 		return r;
315 
316 	r = mgr->apply(mgr);
317 	if (r)
318 		return r;
319 
320 	return size;
321 }
322 
323 static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,
324 		char *buf)
325 {
326 	struct omap_overlay_manager_info info;
327 
328 	mgr->get_manager_info(mgr, &info);
329 
330 	return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable);
331 }
332 
333 static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,
334 		const char *buf, size_t size)
335 {
336 	struct omap_overlay_manager_info info;
337 	int r;
338 	bool enable;
339 
340 	if (!dss_has_feature(FEAT_CPR))
341 		return -ENODEV;
342 
343 	r = strtobool(buf, &enable);
344 	if (r)
345 		return r;
346 
347 	mgr->get_manager_info(mgr, &info);
348 
349 	if (info.cpr_enable == enable)
350 		return size;
351 
352 	info.cpr_enable = enable;
353 
354 	r = mgr->set_manager_info(mgr, &info);
355 	if (r)
356 		return r;
357 
358 	r = mgr->apply(mgr);
359 	if (r)
360 		return r;
361 
362 	return size;
363 }
364 
365 static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr,
366 		char *buf)
367 {
368 	struct omap_overlay_manager_info info;
369 
370 	mgr->get_manager_info(mgr, &info);
371 
372 	return snprintf(buf, PAGE_SIZE,
373 			"%d %d %d %d %d %d %d %d %d\n",
374 			info.cpr_coefs.rr,
375 			info.cpr_coefs.rg,
376 			info.cpr_coefs.rb,
377 			info.cpr_coefs.gr,
378 			info.cpr_coefs.gg,
379 			info.cpr_coefs.gb,
380 			info.cpr_coefs.br,
381 			info.cpr_coefs.bg,
382 			info.cpr_coefs.bb);
383 }
384 
385 static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr,
386 		const char *buf, size_t size)
387 {
388 	struct omap_overlay_manager_info info;
389 	struct omap_dss_cpr_coefs coefs;
390 	int r, i;
391 	s16 *arr;
392 
393 	if (!dss_has_feature(FEAT_CPR))
394 		return -ENODEV;
395 
396 	if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd",
397 				&coefs.rr, &coefs.rg, &coefs.rb,
398 				&coefs.gr, &coefs.gg, &coefs.gb,
399 				&coefs.br, &coefs.bg, &coefs.bb) != 9)
400 		return -EINVAL;
401 
402 	arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb,
403 		coefs.gr, coefs.gg, coefs.gb,
404 		coefs.br, coefs.bg, coefs.bb };
405 
406 	for (i = 0; i < 9; ++i) {
407 		if (arr[i] < -512 || arr[i] > 511)
408 			return -EINVAL;
409 	}
410 
411 	mgr->get_manager_info(mgr, &info);
412 
413 	info.cpr_coefs = coefs;
414 
415 	r = mgr->set_manager_info(mgr, &info);
416 	if (r)
417 		return r;
418 
419 	r = mgr->apply(mgr);
420 	if (r)
421 		return r;
422 
423 	return size;
424 }
425 
426 struct manager_attribute {
427 	struct attribute attr;
428 	ssize_t (*show)(struct omap_overlay_manager *, char *);
429 	ssize_t	(*store)(struct omap_overlay_manager *, const char *, size_t);
430 };
431 
432 #define MANAGER_ATTR(_name, _mode, _show, _store) \
433 	struct manager_attribute manager_attr_##_name = \
434 	__ATTR(_name, _mode, _show, _store)
435 
436 static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
437 static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
438 		manager_display_show, manager_display_store);
439 static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
440 		manager_default_color_show, manager_default_color_store);
441 static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,
442 		manager_trans_key_type_show, manager_trans_key_type_store);
443 static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,
444 		manager_trans_key_value_show, manager_trans_key_value_store);
445 static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
446 		manager_trans_key_enabled_show,
447 		manager_trans_key_enabled_store);
448 static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
449 		manager_alpha_blending_enabled_show,
450 		manager_alpha_blending_enabled_store);
451 static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR,
452 		manager_cpr_enable_show,
453 		manager_cpr_enable_store);
454 static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR,
455 		manager_cpr_coef_show,
456 		manager_cpr_coef_store);
457 
458 
459 static struct attribute *manager_sysfs_attrs[] = {
460 	&manager_attr_name.attr,
461 	&manager_attr_display.attr,
462 	&manager_attr_default_color.attr,
463 	&manager_attr_trans_key_type.attr,
464 	&manager_attr_trans_key_value.attr,
465 	&manager_attr_trans_key_enabled.attr,
466 	&manager_attr_alpha_blending_enabled.attr,
467 	&manager_attr_cpr_enable.attr,
468 	&manager_attr_cpr_coef.attr,
469 	NULL
470 };
471 
472 static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,
473 		char *buf)
474 {
475 	struct omap_overlay_manager *manager;
476 	struct manager_attribute *manager_attr;
477 
478 	manager = container_of(kobj, struct omap_overlay_manager, kobj);
479 	manager_attr = container_of(attr, struct manager_attribute, attr);
480 
481 	if (!manager_attr->show)
482 		return -ENOENT;
483 
484 	return manager_attr->show(manager, buf);
485 }
486 
487 static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
488 		const char *buf, size_t size)
489 {
490 	struct omap_overlay_manager *manager;
491 	struct manager_attribute *manager_attr;
492 
493 	manager = container_of(kobj, struct omap_overlay_manager, kobj);
494 	manager_attr = container_of(attr, struct manager_attribute, attr);
495 
496 	if (!manager_attr->store)
497 		return -ENOENT;
498 
499 	return manager_attr->store(manager, buf, size);
500 }
501 
502 static const struct sysfs_ops manager_sysfs_ops = {
503 	.show = manager_attr_show,
504 	.store = manager_attr_store,
505 };
506 
507 static struct kobj_type manager_ktype = {
508 	.sysfs_ops = &manager_sysfs_ops,
509 	.default_attrs = manager_sysfs_attrs,
510 };
511 
512 int dss_manager_kobj_init(struct omap_overlay_manager *mgr,
513 		struct platform_device *pdev)
514 {
515 	return kobject_init_and_add(&mgr->kobj, &manager_ktype,
516 			&pdev->dev.kobj, "manager%d", mgr->id);
517 }
518 
519 void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr)
520 {
521 	kobject_del(&mgr->kobj);
522 	kobject_put(&mgr->kobj);
523 
524 	memset(&mgr->kobj, 0, sizeof(mgr->kobj));
525 }
526