2 * linux/drivers/video/omap2/dss/manager.c
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
7 * Some code and ideas taken from drivers/video/omap/ driver
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.
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
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/>.
23 #define DSS_SUBSYS_NAME "MANAGER"
25 #include <linux/kernel.h>
26 #include <linux/module.h>
27 #include <linux/platform_device.h>
29 #include <mach/display.h>
33 static int num_managers;
34 static struct list_head manager_list;
36 static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
38 return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
41 static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
43 return snprintf(buf, PAGE_SIZE, "%s\n",
44 mgr->display ? mgr->display->name : "<none>");
47 static ssize_t manager_display_store(struct omap_overlay_manager *mgr, const char *buf, size_t size)
51 struct omap_display *display = NULL;
53 if (buf[size-1] == '\n')
57 for (i = 0; i < omap_dss_get_num_displays(); ++i) {
58 display = dss_get_display(i);
60 if (strncmp(buf, display->name, len) == 0)
67 if (len > 0 && display == NULL)
71 DSSDBG("display %s found\n", display->name);
74 r = mgr->unset_display(mgr);
76 DSSERR("failed to unset display\n");
82 r = mgr->set_display(mgr, display);
84 DSSERR("failed to set manager\n");
90 DSSERR("failed to apply dispc config\n");
98 static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
103 default_color = dispc_get_default_color(mgr->id);
104 return snprintf(buf, PAGE_SIZE, "%d", default_color);
107 static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
108 const char *buf, size_t size)
112 if (sscanf(buf, "%d", &default_color) != 1)
114 dispc_set_default_color(mgr->id, default_color);
119 static const char *color_key_type_str[] = {
124 static ssize_t manager_color_key_type_show(struct omap_overlay_manager *mgr,
127 enum omap_dss_color_key_type key_type;
129 dispc_get_trans_key(mgr->id, &key_type, NULL);
130 BUG_ON(key_type >= ARRAY_SIZE(color_key_type_str));
132 return snprintf(buf, PAGE_SIZE, "%s\n", color_key_type_str[key_type]);
135 static ssize_t manager_color_key_type_store(struct omap_overlay_manager *mgr,
136 const char *buf, size_t size)
138 enum omap_dss_color_key_type key_type;
141 for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
142 key_type < ARRAY_SIZE(color_key_type_str); key_type++) {
143 if (sysfs_streq(buf, color_key_type_str[key_type]))
146 if (key_type == ARRAY_SIZE(color_key_type_str))
148 dispc_get_trans_key(mgr->id, NULL, &key_value);
149 dispc_set_trans_key(mgr->id, key_type, key_value);
154 static ssize_t manager_color_key_value_show(struct omap_overlay_manager *mgr,
159 dispc_get_trans_key(mgr->id, NULL, &key_value);
161 return snprintf(buf, PAGE_SIZE, "%d\n", key_value);
164 static ssize_t manager_color_key_value_store(struct omap_overlay_manager *mgr,
165 const char *buf, size_t size)
167 enum omap_dss_color_key_type key_type;
170 if (sscanf(buf, "%d", &key_value) != 1)
172 dispc_get_trans_key(mgr->id, &key_type, NULL);
173 dispc_set_trans_key(mgr->id, key_type, key_value);
178 static ssize_t manager_color_key_enabled_show(struct omap_overlay_manager *mgr,
181 return snprintf(buf, PAGE_SIZE, "%d\n",
182 dispc_trans_key_enabled(mgr->id));
185 static ssize_t manager_color_key_enabled_store(struct omap_overlay_manager *mgr,
186 const char *buf, size_t size)
190 if (sscanf(buf, "%d", &enable) != 1)
193 dispc_enable_trans_key(mgr->id, enable);
199 struct manager_attribute {
200 struct attribute attr;
201 ssize_t (*show)(struct omap_overlay_manager *, char *);
202 ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);
205 #define MANAGER_ATTR(_name, _mode, _show, _store) \
206 struct manager_attribute manager_attr_##_name = \
207 __ATTR(_name, _mode, _show, _store)
209 static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
210 static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
211 manager_display_show, manager_display_store);
212 static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
213 manager_default_color_show, manager_default_color_store);
214 static MANAGER_ATTR(color_key_type, S_IRUGO|S_IWUSR,
215 manager_color_key_type_show, manager_color_key_type_store);
216 static MANAGER_ATTR(color_key_value, S_IRUGO|S_IWUSR,
217 manager_color_key_value_show, manager_color_key_value_store);
218 static MANAGER_ATTR(color_key_enabled, S_IRUGO|S_IWUSR,
219 manager_color_key_enabled_show, manager_color_key_enabled_store);
221 static struct attribute *manager_sysfs_attrs[] = {
222 &manager_attr_name.attr,
223 &manager_attr_display.attr,
224 &manager_attr_default_color.attr,
225 &manager_attr_color_key_type.attr,
226 &manager_attr_color_key_value.attr,
227 &manager_attr_color_key_enabled.attr,
231 static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
233 struct omap_overlay_manager *manager;
234 struct manager_attribute *manager_attr;
236 manager = container_of(kobj, struct omap_overlay_manager, kobj);
237 manager_attr = container_of(attr, struct manager_attribute, attr);
239 if (!manager_attr->show)
242 return manager_attr->show(manager, buf);
245 static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
246 const char *buf, size_t size)
248 struct omap_overlay_manager *manager;
249 struct manager_attribute *manager_attr;
251 manager = container_of(kobj, struct omap_overlay_manager, kobj);
252 manager_attr = container_of(attr, struct manager_attribute, attr);
254 if (!manager_attr->store)
257 return manager_attr->store(manager, buf, size);
260 static struct sysfs_ops manager_sysfs_ops = {
261 .show = manager_attr_show,
262 .store = manager_attr_store,
265 static struct kobj_type manager_ktype = {
266 .sysfs_ops = &manager_sysfs_ops,
267 .default_attrs = manager_sysfs_attrs,
270 static int omap_dss_set_display(struct omap_overlay_manager *mgr,
271 struct omap_display *display)
276 if (display->manager) {
277 DSSERR("display '%s' already has a manager '%s'\n",
278 display->name, display->manager->name);
282 if ((mgr->supported_displays & display->type) == 0) {
283 DSSERR("display '%s' does not support manager '%s'\n",
284 display->name, mgr->name);
288 for (i = 0; i < mgr->num_overlays; i++) {
289 struct omap_overlay *ovl = mgr->overlays[i];
291 if (ovl->manager != mgr || !ovl->info.enabled)
294 r = dss_check_overlay(ovl, display);
299 display->manager = mgr;
300 mgr->display = display;
305 static int omap_dss_unset_display(struct omap_overlay_manager *mgr)
308 DSSERR("failed to unset display, display not set.\n");
312 mgr->display->manager = NULL;
319 static int overlay_enabled(struct omap_overlay *ovl)
321 return ovl->info.enabled && ovl->manager && ovl->manager->display;
324 /* We apply settings to both managers here so that we can use optimizations
325 * like fifomerge. Shadow registers can be changed first and the non-shadowed
326 * should be changed last, at the same time with GO */
327 static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
331 enum omap_dss_update_mode mode;
332 struct omap_display *display;
333 struct omap_overlay *ovl;
337 int num_planes_enabled = 0;
339 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
341 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
343 /* Configure normal overlay parameters and disable unused overlays */
344 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
345 ovl = omap_dss_get_overlay(i);
347 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
350 if (!overlay_enabled(ovl)) {
351 dispc_enable_plane(ovl->id, 0);
355 display = ovl->manager->display;
357 if (dss_check_overlay(ovl, display)) {
358 dispc_enable_plane(ovl->id, 0);
362 ++num_planes_enabled;
364 /* On a manual update display, in manual update mode, update()
365 * handles configuring planes */
366 mode = OMAP_DSS_UPDATE_AUTO;
367 if (display->get_update_mode)
368 mode = display->get_update_mode(mgr->display);
370 if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
371 mode != OMAP_DSS_UPDATE_AUTO)
374 if (display->type == OMAP_DISPLAY_TYPE_VENC)
377 if (ovl->info.out_width == 0)
378 outw = ovl->info.width;
380 outw = ovl->info.out_width;
382 if (ovl->info.out_height == 0)
383 outh = ovl->info.height;
385 outh = ovl->info.out_height;
387 r = dispc_setup_plane(ovl->id, ovl->manager->id,
389 ovl->info.screen_width,
396 ovl->info.color_mode,
398 ovl->info.rotation_type,
403 DSSERR("dispc_setup_plane failed for ovl %d\n",
405 dispc_enable_plane(ovl->id, 0);
409 dispc_enable_plane(ovl->id, 1);
412 /* Enable fifo merge if possible */
413 dispc_enable_fifomerge(num_planes_enabled == 1);
415 /* Go through overlays again. This time we configure fifos. We have to
416 * do this after enabling/disabling fifomerge so that we have correct
417 * knowledge of fifo sizes */
418 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
419 ovl = omap_dss_get_overlay(i);
421 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
424 if (!overlay_enabled(ovl)) {
428 ovl->manager->display->configure_overlay(ovl);
431 /* Issue GO for managers */
432 list_for_each_entry(mgr, &manager_list, list) {
433 if (!(mgr->caps & OMAP_DSS_OVL_MGR_CAP_DISPC))
436 display = mgr->display;
441 /* We don't need GO with manual update display. LCD iface will
442 * always be turned off after frame, and new settings will
443 * be taken in to use at next update */
444 if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
450 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
455 static void omap_dss_mgr_set_def_color(struct omap_overlay_manager *mgr,
458 dispc_set_default_color(mgr->id, color);
461 static void omap_dss_mgr_set_trans_key(struct omap_overlay_manager *mgr,
462 enum omap_dss_color_key_type type,
465 dispc_set_trans_key(mgr->id, type, trans_key);
468 static void omap_dss_mgr_enable_trans_key(struct omap_overlay_manager *mgr,
471 dispc_enable_trans_key(mgr->id, enable);
474 static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager)
477 list_add_tail(&manager->list, &manager_list);
480 int dss_init_overlay_managers(struct platform_device *pdev)
484 INIT_LIST_HEAD(&manager_list);
488 for (i = 0; i < 2; ++i) {
489 struct omap_overlay_manager *mgr;
490 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
497 mgr->id = OMAP_DSS_CHANNEL_LCD;
498 mgr->supported_displays =
499 OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
500 OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI;
504 mgr->id = OMAP_DSS_CHANNEL_DIGIT;
505 mgr->supported_displays = OMAP_DISPLAY_TYPE_VENC;
509 mgr->set_display = &omap_dss_set_display,
510 mgr->unset_display = &omap_dss_unset_display,
511 mgr->apply = &omap_dss_mgr_apply,
512 mgr->set_default_color = &omap_dss_mgr_set_def_color,
513 mgr->set_trans_key = &omap_dss_mgr_set_trans_key,
514 mgr->enable_trans_key = &omap_dss_mgr_enable_trans_key,
515 mgr->caps = OMAP_DSS_OVL_MGR_CAP_DISPC,
517 dss_overlay_setup_dispc_manager(mgr);
519 omap_dss_add_overlay_manager(mgr);
521 r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
522 &pdev->dev.kobj, "manager%d", i);
525 DSSERR("failed to create sysfs file\n");
533 void dss_uninit_overlay_managers(struct platform_device *pdev)
535 struct omap_overlay_manager *mgr;
537 while (!list_empty(&manager_list)) {
538 mgr = list_first_entry(&manager_list,
539 struct omap_overlay_manager, list);
540 list_del(&mgr->list);
541 kobject_del(&mgr->kobj);
542 kobject_put(&mgr->kobj);
549 int omap_dss_get_num_overlay_managers(void)
553 EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
555 struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
558 struct omap_overlay_manager *mgr;
560 list_for_each_entry(mgr, &manager_list, list) {
567 EXPORT_SYMBOL(omap_dss_get_overlay_manager);
570 static int ovl_mgr_apply_l4(struct omap_overlay_manager *mgr)
572 DSSDBG("omap_dss_mgr_apply_l4(%s)\n", mgr->name);