e0501c493faf7c0ea41e61af925643c275f90952
[pandora-kernel.git] / drivers / video / omap2 / dss / manager.c
1 /*
2  * linux/drivers/video/omap2/dss/manager.c
3  *
4  * Copyright (C) 2009 Nokia Corporation
5  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6  *
7  * Some code and ideas taken from drivers/video/omap/ driver
8  * by Imre Deak.
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License version 2 as published by
12  * the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
17  * more details.
18  *
19  * You should have received a copy of the GNU General Public License along with
20  * this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #define DSS_SUBSYS_NAME "MANAGER"
24
25 #include <linux/kernel.h>
26 #include <linux/module.h>
27 #include <linux/platform_device.h>
28
29 #include <mach/display.h>
30
31 #include "dss.h"
32
33 static int num_managers;
34 static struct list_head manager_list;
35
36 static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
37 {
38         return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
39 }
40
41 static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
42 {
43         return snprintf(buf, PAGE_SIZE, "%s\n",
44                         mgr->display ? mgr->display->name : "<none>");
45 }
46
47 static ssize_t manager_display_store(struct omap_overlay_manager *mgr, const char *buf, size_t size)
48 {
49         int r, i;
50         int len = size;
51         struct omap_display *display = NULL;
52
53         if (buf[size-1] == '\n')
54                 --len;
55
56         if (len > 0) {
57                 for (i = 0; i < omap_dss_get_num_displays(); ++i) {
58                         display = dss_get_display(i);
59
60                         if (strncmp(buf, display->name, len) == 0)
61                                 break;
62
63                         display = NULL;
64                 }
65         }
66
67         if (len > 0 && display == NULL)
68                 return -EINVAL;
69
70         if (display)
71                 DSSDBG("display %s found\n", display->name);
72
73         if (mgr->display) {
74                 r = mgr->unset_display(mgr);
75                 if (r) {
76                         DSSERR("failed to unset display\n");
77                         return r;
78                 }
79         }
80
81         if (display) {
82                 r = mgr->set_display(mgr, display);
83                 if (r) {
84                         DSSERR("failed to set manager\n");
85                         return r;
86                 }
87
88                 r = mgr->apply(mgr);
89                 if (r) {
90                         DSSERR("failed to apply dispc config\n");
91                         return r;
92                 }
93         }
94
95         return size;
96 }
97
98 static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
99                                           char *buf)
100 {
101         return snprintf(buf, PAGE_SIZE, "%d",
102                         mgr->get_default_color(mgr));
103 }
104
105 static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
106                                            const char *buf, size_t size)
107 {
108         u32 default_color;
109
110         if (sscanf(buf, "%d", &default_color) != 1)
111                 return -EINVAL;
112         dispc_set_default_color(mgr->id, default_color);
113
114         return size;
115 }
116
117 static const char *color_key_type_str[] = {
118         "gfx-destination",
119         "video-source",
120 };
121
122 static ssize_t manager_color_key_type_show(struct omap_overlay_manager *mgr,
123                                            char *buf)
124 {
125         enum omap_dss_color_key_type key_type;
126
127         mgr->get_trans_key_type_and_value(mgr, &key_type, NULL);
128         BUG_ON(key_type >= ARRAY_SIZE(color_key_type_str));
129
130         return snprintf(buf, PAGE_SIZE, "%s\n", color_key_type_str[key_type]);
131 }
132
133 static ssize_t manager_color_key_type_store(struct omap_overlay_manager *mgr,
134                                             const char *buf, size_t size)
135 {
136         enum omap_dss_color_key_type key_type;
137         u32 key_value;
138
139         for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
140              key_type < ARRAY_SIZE(color_key_type_str); key_type++) {
141                 if (sysfs_streq(buf, color_key_type_str[key_type]))
142                         break;
143         }
144         if (key_type == ARRAY_SIZE(color_key_type_str))
145                 return -EINVAL;
146         mgr->get_trans_key_type_and_value(mgr, NULL, &key_value);
147         mgr->set_trans_key_type_and_value(mgr, key_type, key_value);
148
149         return size;
150 }
151
152 static ssize_t manager_color_key_value_show(struct omap_overlay_manager *mgr,
153                                             char *buf)
154 {
155         u32 key_value;
156
157          mgr->get_trans_key_type_and_value(mgr, NULL, &key_value);
158
159         return snprintf(buf, PAGE_SIZE, "%d\n", key_value);
160 }
161
162 static ssize_t manager_color_key_value_store(struct omap_overlay_manager *mgr,
163                                              const char *buf, size_t size)
164 {
165         enum omap_dss_color_key_type key_type;
166         u32 key_value;
167
168         if (sscanf(buf, "%d", &key_value) != 1)
169                 return -EINVAL;
170         mgr->get_trans_key_type_and_value(mgr, &key_type, NULL);
171         mgr->set_trans_key_type_and_value(mgr, key_type, key_value);
172
173         return size;
174 }
175
176 static ssize_t manager_color_key_enabled_show(struct omap_overlay_manager *mgr,
177                                               char *buf)
178 {
179         return snprintf(buf, PAGE_SIZE, "%d\n",
180         mgr->get_trans_key_status(mgr));
181 }
182
183 static ssize_t manager_color_key_enabled_store(struct omap_overlay_manager *mgr,
184                                                const char *buf, size_t size)
185 {
186         int enable;
187
188         if (sscanf(buf, "%d", &enable) != 1)
189                 return -EINVAL;
190
191         mgr->enable_trans_key(mgr, enable);
192
193         return size;
194 }
195
196
197 struct manager_attribute {
198         struct attribute attr;
199         ssize_t (*show)(struct omap_overlay_manager *, char *);
200         ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);
201 };
202
203 #define MANAGER_ATTR(_name, _mode, _show, _store) \
204         struct manager_attribute manager_attr_##_name = \
205         __ATTR(_name, _mode, _show, _store)
206
207 static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
208 static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
209                 manager_display_show, manager_display_store);
210 static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
211                 manager_default_color_show, manager_default_color_store);
212 static MANAGER_ATTR(color_key_type, S_IRUGO|S_IWUSR,
213                 manager_color_key_type_show, manager_color_key_type_store);
214 static MANAGER_ATTR(color_key_value, S_IRUGO|S_IWUSR,
215                 manager_color_key_value_show, manager_color_key_value_store);
216 static MANAGER_ATTR(color_key_enabled, S_IRUGO|S_IWUSR,
217                 manager_color_key_enabled_show, manager_color_key_enabled_store);
218
219 static struct attribute *manager_sysfs_attrs[] = {
220         &manager_attr_name.attr,
221         &manager_attr_display.attr,
222         &manager_attr_default_color.attr,
223         &manager_attr_color_key_type.attr,
224         &manager_attr_color_key_value.attr,
225         &manager_attr_color_key_enabled.attr,
226         NULL
227 };
228
229 static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
230 {
231         struct omap_overlay_manager *manager;
232         struct manager_attribute *manager_attr;
233
234         manager = container_of(kobj, struct omap_overlay_manager, kobj);
235         manager_attr = container_of(attr, struct manager_attribute, attr);
236
237         if (!manager_attr->show)
238                 return -ENOENT;
239
240         return manager_attr->show(manager, buf);
241 }
242
243 static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
244                 const char *buf, size_t size)
245 {
246         struct omap_overlay_manager *manager;
247         struct manager_attribute *manager_attr;
248
249         manager = container_of(kobj, struct omap_overlay_manager, kobj);
250         manager_attr = container_of(attr, struct manager_attribute, attr);
251
252         if (!manager_attr->store)
253                 return -ENOENT;
254
255         return manager_attr->store(manager, buf, size);
256 }
257
258 static struct sysfs_ops manager_sysfs_ops = {
259         .show = manager_attr_show,
260         .store = manager_attr_store,
261 };
262
263 static struct kobj_type manager_ktype = {
264         .sysfs_ops = &manager_sysfs_ops,
265         .default_attrs = manager_sysfs_attrs,
266 };
267
268 static int omap_dss_set_display(struct omap_overlay_manager *mgr,
269                 struct omap_display *display)
270 {
271         int i;
272         int r;
273
274         if (display->manager) {
275                 DSSERR("display '%s' already has a manager '%s'\n",
276                                display->name, display->manager->name);
277                 return -EINVAL;
278         }
279
280         if ((mgr->supported_displays & display->type) == 0) {
281                 DSSERR("display '%s' does not support manager '%s'\n",
282                                display->name, mgr->name);
283                 return -EINVAL;
284         }
285
286         for (i = 0; i < mgr->num_overlays; i++) {
287                 struct omap_overlay *ovl = mgr->overlays[i];
288
289                 if (ovl->manager != mgr || !ovl->info.enabled)
290                         continue;
291
292                 r = dss_check_overlay(ovl, display);
293                 if (r)
294                         return r;
295         }
296
297         display->manager = mgr;
298         mgr->display = display;
299
300         return 0;
301 }
302
303 static int omap_dss_unset_display(struct omap_overlay_manager *mgr)
304 {
305         if (!mgr->display) {
306                 DSSERR("failed to unset display, display not set.\n");
307                 return -EINVAL;
308         }
309
310         mgr->display->manager = NULL;
311         mgr->display = NULL;
312
313         return 0;
314 }
315
316
317 static int overlay_enabled(struct omap_overlay *ovl)
318 {
319         return ovl->info.enabled && ovl->manager && ovl->manager->display;
320 }
321
322 /* We apply settings to both managers here so that we can use optimizations
323  * like fifomerge. Shadow registers can be changed first and the non-shadowed
324  * should be changed last, at the same time with GO */
325 static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
326 {
327         int i;
328         int ret = 0;
329         enum omap_dss_update_mode mode;
330         struct omap_display *display;
331         struct omap_overlay *ovl;
332         bool ilace = 0;
333         int outw, outh;
334         int r;
335         int num_planes_enabled = 0;
336
337         DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
338
339         dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
340
341         /* Configure normal overlay parameters and disable unused overlays */
342         for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
343                 ovl = omap_dss_get_overlay(i);
344
345                 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
346                         continue;
347
348                 if (!overlay_enabled(ovl)) {
349                         dispc_enable_plane(ovl->id, 0);
350                         continue;
351                 }
352
353                 display = ovl->manager->display;
354
355                 if (dss_check_overlay(ovl, display)) {
356                         dispc_enable_plane(ovl->id, 0);
357                         continue;
358                 }
359
360                 ++num_planes_enabled;
361
362                 /* On a manual update display, in manual update mode, update()
363                  * handles configuring planes */
364                 mode = OMAP_DSS_UPDATE_AUTO;
365                 if (display->get_update_mode)
366                         mode = display->get_update_mode(mgr->display);
367
368                 if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
369                                 mode != OMAP_DSS_UPDATE_AUTO)
370                         continue;
371
372                 if (display->type == OMAP_DISPLAY_TYPE_VENC)
373                         ilace = 1;
374
375                 if (ovl->info.out_width == 0)
376                         outw = ovl->info.width;
377                 else
378                         outw = ovl->info.out_width;
379
380                 if (ovl->info.out_height == 0)
381                         outh = ovl->info.height;
382                 else
383                         outh = ovl->info.out_height;
384
385                 r = dispc_setup_plane(ovl->id, ovl->manager->id,
386                                 ovl->info.paddr,
387                                 ovl->info.screen_width,
388                                 ovl->info.pos_x,
389                                 ovl->info.pos_y,
390                                 ovl->info.width,
391                                 ovl->info.height,
392                                 outw,
393                                 outh,
394                                 ovl->info.color_mode,
395                                 ilace,
396                                 ovl->info.rotation_type,
397                                 ovl->info.rotation,
398                                 ovl->info.mirror);
399
400                 if (r) {
401                         DSSERR("dispc_setup_plane failed for ovl %d\n",
402                                         ovl->id);
403                         dispc_enable_plane(ovl->id, 0);
404                         continue;
405                 }
406
407                 dispc_enable_plane(ovl->id, 1);
408         }
409
410         /* Enable fifo merge if possible */
411         dispc_enable_fifomerge(num_planes_enabled == 1);
412
413         /* Go through overlays again. This time we configure fifos.  We have to
414          * do this after enabling/disabling fifomerge so that we have correct
415          * knowledge of fifo sizes */
416         for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
417                 ovl = omap_dss_get_overlay(i);
418
419                 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
420                         continue;
421
422                 if (!overlay_enabled(ovl)) {
423                         continue;
424                 }
425
426                 ovl->manager->display->configure_overlay(ovl);
427         }
428
429         /* Issue GO for managers */
430         list_for_each_entry(mgr, &manager_list, list) {
431                 if (!(mgr->caps & OMAP_DSS_OVL_MGR_CAP_DISPC))
432                         continue;
433
434                 display = mgr->display;
435
436                 if (!display)
437                         continue;
438
439                 /* We don't need GO with manual update display. LCD iface will
440                  * always be turned off after frame, and new settings will
441                  * be taken in to use at next update */
442                 if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
443                         continue;
444
445                 dispc_go(mgr->id);
446         }
447
448         dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
449
450         return ret;
451 }
452
453 static void omap_dss_mgr_set_def_color(struct omap_overlay_manager *mgr,
454                 u32 color)
455 {
456         dispc_set_default_color(mgr->id, color);
457 }
458
459 static void omap_dss_mgr_set_trans_key_type_and_value(
460                 struct omap_overlay_manager *mgr,
461                 enum omap_dss_color_key_type type,
462                 u32 trans_key)
463 {
464         dispc_set_trans_key(mgr->id, type, trans_key);
465 }
466 static void omap_dss_mgr_get_trans_key_type_and_value(
467                 struct omap_overlay_manager *mgr,
468                 enum omap_dss_color_key_type *type,
469                 u32 *trans_key)
470 {
471         dispc_get_trans_key(mgr->id, type, trans_key);
472 }
473
474 static void omap_dss_mgr_enable_trans_key(struct omap_overlay_manager *mgr,
475                 bool enable)
476 {
477         dispc_enable_trans_key(mgr->id, enable);
478 }
479 static void omap_dss_mgr_enable_alpha_blending(struct omap_overlay_manager *mgr,
480                 bool enable)
481 {
482         dispc_enable_alpha_blending(mgr->id, enable);
483 }
484 static bool omap_dss_mgr_get_alpha_blending_status(
485                 struct omap_overlay_manager *mgr)
486 {
487         return dispc_alpha_blending_enabled(mgr->id);
488 }
489 static u32 omap_dss_mgr_get_default_color(struct omap_overlay_manager *mgr)
490 {
491         return dispc_get_default_color(mgr->id);
492 }
493 static bool omap_dss_mgr_get_trans_key_status(struct omap_overlay_manager *mgr)
494 {
495         return dispc_trans_key_enabled(mgr->id);
496 }
497
498 static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager)
499 {
500         ++num_managers;
501         list_add_tail(&manager->list, &manager_list);
502 }
503
504 int dss_init_overlay_managers(struct platform_device *pdev)
505 {
506         int i, r;
507
508         INIT_LIST_HEAD(&manager_list);
509
510         num_managers = 0;
511
512         for (i = 0; i < 2; ++i) {
513                 struct omap_overlay_manager *mgr;
514                 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
515
516                 BUG_ON(mgr == NULL);
517
518                 switch (i) {
519                 case 0:
520                         mgr->name = "lcd";
521                         mgr->id = OMAP_DSS_CHANNEL_LCD;
522                         mgr->supported_displays =
523                                 OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
524                                 OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI;
525                         break;
526                 case 1:
527                         mgr->name = "tv";
528                         mgr->id = OMAP_DSS_CHANNEL_DIGIT;
529                         mgr->supported_displays = OMAP_DISPLAY_TYPE_VENC;
530                         break;
531                 }
532
533                 mgr->set_display = &omap_dss_set_display,
534                 mgr->unset_display = &omap_dss_unset_display,
535                 mgr->apply = &omap_dss_mgr_apply,
536                 mgr->set_default_color = &omap_dss_mgr_set_def_color,
537                 mgr->set_trans_key_type_and_value =
538                         &omap_dss_mgr_set_trans_key_type_and_value,
539                 mgr->get_trans_key_type_and_value =
540                         &omap_dss_mgr_get_trans_key_type_and_value,
541                 mgr->enable_trans_key = &omap_dss_mgr_enable_trans_key,
542                 mgr->get_trans_key_status = &omap_dss_mgr_get_trans_key_status,
543                 mgr->enable_alpha_blending =
544                         &omap_dss_mgr_enable_alpha_blending;
545                 mgr->get_alpha_blending_status =
546                         omap_dss_mgr_get_alpha_blending_status;
547                 mgr->get_default_color = &omap_dss_mgr_get_default_color;
548                 mgr->caps = OMAP_DSS_OVL_MGR_CAP_DISPC,
549
550                 dss_overlay_setup_dispc_manager(mgr);
551
552                 omap_dss_add_overlay_manager(mgr);
553
554                 r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
555                                 &pdev->dev.kobj, "manager%d", i);
556
557                 if (r) {
558                         DSSERR("failed to create sysfs file\n");
559                         continue;
560                 }
561         }
562
563         return 0;
564 }
565
566 void dss_uninit_overlay_managers(struct platform_device *pdev)
567 {
568         struct omap_overlay_manager *mgr;
569
570         while (!list_empty(&manager_list)) {
571                 mgr = list_first_entry(&manager_list,
572                                 struct omap_overlay_manager, list);
573                 list_del(&mgr->list);
574                 kobject_del(&mgr->kobj);
575                 kobject_put(&mgr->kobj);
576                 kfree(mgr);
577         }
578
579         num_managers = 0;
580 }
581
582 int omap_dss_get_num_overlay_managers(void)
583 {
584         return num_managers;
585 }
586 EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
587
588 struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
589 {
590         int i = 0;
591         struct omap_overlay_manager *mgr;
592
593         list_for_each_entry(mgr, &manager_list, list) {
594                 if (i++ == num)
595                         return mgr;
596         }
597
598         return NULL;
599 }
600 EXPORT_SYMBOL(omap_dss_get_overlay_manager);
601
602 #ifdef L4_EXAMPLE
603 static int ovl_mgr_apply_l4(struct omap_overlay_manager *mgr)
604 {
605         DSSDBG("omap_dss_mgr_apply_l4(%s)\n", mgr->name);
606
607         return 0;
608 }
609 #endif
610