1690 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2011 Texas Instruments4 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>5 */6 7#define DSS_SUBSYS_NAME "APPLY"8 9#include <linux/kernel.h>10#include <linux/module.h>11#include <linux/slab.h>12#include <linux/spinlock.h>13#include <linux/jiffies.h>14 15#include <video/omapfb_dss.h>16 17#include "dss.h"18#include "dss_features.h"19#include "dispc-compat.h"20 21/*22 * We have 4 levels of cache for the dispc settings. First two are in SW and23 * the latter two in HW.24 *25 * set_info()26 * v27 * +--------------------+28 * | user_info |29 * +--------------------+30 * v31 * apply()32 * v33 * +--------------------+34 * | info |35 * +--------------------+36 * v37 * write_regs()38 * v39 * +--------------------+40 * | shadow registers |41 * +--------------------+42 * v43 * VFP or lcd/digit_enable44 * v45 * +--------------------+46 * | registers |47 * +--------------------+48 */49 50struct ovl_priv_data {51 52 bool user_info_dirty;53 struct omap_overlay_info user_info;54 55 bool info_dirty;56 struct omap_overlay_info info;57 58 bool shadow_info_dirty;59 60 bool extra_info_dirty;61 bool shadow_extra_info_dirty;62 63 bool enabled;64 u32 fifo_low, fifo_high;65 66 /*67 * True if overlay is to be enabled. Used to check and calculate configs68 * for the overlay before it is enabled in the HW.69 */70 bool enabling;71};72 73struct mgr_priv_data {74 75 bool user_info_dirty;76 struct omap_overlay_manager_info user_info;77 78 bool info_dirty;79 struct omap_overlay_manager_info info;80 81 bool shadow_info_dirty;82 83 /* If true, GO bit is up and shadow registers cannot be written.84 * Never true for manual update displays */85 bool busy;86 87 /* If true, dispc output is enabled */88 bool updating;89 90 /* If true, a display is enabled using this manager */91 bool enabled;92 93 bool extra_info_dirty;94 bool shadow_extra_info_dirty;95 96 struct omap_video_timings timings;97 struct dss_lcd_mgr_config lcd_config;98 99 void (*framedone_handler)(void *);100 void *framedone_handler_data;101};102 103static struct {104 struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];105 struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];106 107 bool irq_enabled;108} dss_data;109 110/* protects dss_data */111static DEFINE_SPINLOCK(data_lock);112/* lock for blocking functions */113static DEFINE_MUTEX(apply_lock);114static DECLARE_COMPLETION(extra_updated_completion);115 116static void dss_register_vsync_isr(void);117 118static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)119{120 return &dss_data.ovl_priv_data_array[ovl->id];121}122 123static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)124{125 return &dss_data.mgr_priv_data_array[mgr->id];126}127 128static void apply_init_priv(void)129{130 const int num_ovls = dss_feat_get_num_ovls();131 struct mgr_priv_data *mp;132 int i;133 134 for (i = 0; i < num_ovls; ++i) {135 struct ovl_priv_data *op;136 137 op = &dss_data.ovl_priv_data_array[i];138 139 op->info.color_mode = OMAP_DSS_COLOR_RGB16;140 op->info.rotation_type = OMAP_DSS_ROT_DMA;141 142 op->info.global_alpha = 255;143 144 switch (i) {145 case 0:146 op->info.zorder = 0;147 break;148 case 1:149 op->info.zorder =150 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;151 break;152 case 2:153 op->info.zorder =154 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;155 break;156 case 3:157 op->info.zorder =158 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;159 break;160 }161 162 op->user_info = op->info;163 }164 165 /*166 * Initialize some of the lcd_config fields for TV manager, this lets167 * us prevent checking if the manager is LCD or TV at some places168 */169 mp = &dss_data.mgr_priv_data_array[OMAP_DSS_CHANNEL_DIGIT];170 171 mp->lcd_config.video_port_width = 24;172 mp->lcd_config.clock_info.lck_div = 1;173 mp->lcd_config.clock_info.pck_div = 1;174}175 176/*177 * A LCD manager's stallmode decides whether it is in manual or auto update. TV178 * manager is always auto update, stallmode field for TV manager is false by179 * default180 */181static bool ovl_manual_update(struct omap_overlay *ovl)182{183 struct mgr_priv_data *mp = get_mgr_priv(ovl->manager);184 185 return mp->lcd_config.stallmode;186}187 188static bool mgr_manual_update(struct omap_overlay_manager *mgr)189{190 struct mgr_priv_data *mp = get_mgr_priv(mgr);191 192 return mp->lcd_config.stallmode;193}194 195static int dss_check_settings_low(struct omap_overlay_manager *mgr,196 bool applying)197{198 struct omap_overlay_info *oi;199 struct omap_overlay_manager_info *mi;200 struct omap_overlay *ovl;201 struct omap_overlay_info *ois[MAX_DSS_OVERLAYS];202 struct ovl_priv_data *op;203 struct mgr_priv_data *mp;204 205 mp = get_mgr_priv(mgr);206 207 if (!mp->enabled)208 return 0;209 210 if (applying && mp->user_info_dirty)211 mi = &mp->user_info;212 else213 mi = &mp->info;214 215 /* collect the infos to be tested into the array */216 list_for_each_entry(ovl, &mgr->overlays, list) {217 op = get_ovl_priv(ovl);218 219 if (!op->enabled && !op->enabling)220 oi = NULL;221 else if (applying && op->user_info_dirty)222 oi = &op->user_info;223 else224 oi = &op->info;225 226 ois[ovl->id] = oi;227 }228 229 return dss_mgr_check(mgr, mi, &mp->timings, &mp->lcd_config, ois);230}231 232/*233 * check manager and overlay settings using overlay_info from data->info234 */235static int dss_check_settings(struct omap_overlay_manager *mgr)236{237 return dss_check_settings_low(mgr, false);238}239 240/*241 * check manager and overlay settings using overlay_info from ovl->info if242 * dirty and from data->info otherwise243 */244static int dss_check_settings_apply(struct omap_overlay_manager *mgr)245{246 return dss_check_settings_low(mgr, true);247}248 249static bool need_isr(void)250{251 const int num_mgrs = dss_feat_get_num_mgrs();252 int i;253 254 for (i = 0; i < num_mgrs; ++i) {255 struct omap_overlay_manager *mgr;256 struct mgr_priv_data *mp;257 struct omap_overlay *ovl;258 259 mgr = omap_dss_get_overlay_manager(i);260 mp = get_mgr_priv(mgr);261 262 if (!mp->enabled)263 continue;264 265 if (mgr_manual_update(mgr)) {266 /* to catch FRAMEDONE */267 if (mp->updating)268 return true;269 } else {270 /* to catch GO bit going down */271 if (mp->busy)272 return true;273 274 /* to write new values to registers */275 if (mp->info_dirty)276 return true;277 278 /* to set GO bit */279 if (mp->shadow_info_dirty)280 return true;281 282 /*283 * NOTE: we don't check extra_info flags for disabled284 * managers, once the manager is enabled, the extra_info285 * related manager changes will be taken in by HW.286 */287 288 /* to write new values to registers */289 if (mp->extra_info_dirty)290 return true;291 292 /* to set GO bit */293 if (mp->shadow_extra_info_dirty)294 return true;295 296 list_for_each_entry(ovl, &mgr->overlays, list) {297 struct ovl_priv_data *op;298 299 op = get_ovl_priv(ovl);300 301 /*302 * NOTE: we check extra_info flags even for303 * disabled overlays, as extra_infos need to be304 * always written.305 */306 307 /* to write new values to registers */308 if (op->extra_info_dirty)309 return true;310 311 /* to set GO bit */312 if (op->shadow_extra_info_dirty)313 return true;314 315 if (!op->enabled)316 continue;317 318 /* to write new values to registers */319 if (op->info_dirty)320 return true;321 322 /* to set GO bit */323 if (op->shadow_info_dirty)324 return true;325 }326 }327 }328 329 return false;330}331 332static bool need_go(struct omap_overlay_manager *mgr)333{334 struct omap_overlay *ovl;335 struct mgr_priv_data *mp;336 struct ovl_priv_data *op;337 338 mp = get_mgr_priv(mgr);339 340 if (mp->shadow_info_dirty || mp->shadow_extra_info_dirty)341 return true;342 343 list_for_each_entry(ovl, &mgr->overlays, list) {344 op = get_ovl_priv(ovl);345 if (op->shadow_info_dirty || op->shadow_extra_info_dirty)346 return true;347 }348 349 return false;350}351 352/* returns true if an extra_info field is currently being updated */353static bool extra_info_update_ongoing(void)354{355 const int num_mgrs = dss_feat_get_num_mgrs();356 int i;357 358 for (i = 0; i < num_mgrs; ++i) {359 struct omap_overlay_manager *mgr;360 struct omap_overlay *ovl;361 struct mgr_priv_data *mp;362 363 mgr = omap_dss_get_overlay_manager(i);364 mp = get_mgr_priv(mgr);365 366 if (!mp->enabled)367 continue;368 369 if (!mp->updating)370 continue;371 372 if (mp->extra_info_dirty || mp->shadow_extra_info_dirty)373 return true;374 375 list_for_each_entry(ovl, &mgr->overlays, list) {376 struct ovl_priv_data *op = get_ovl_priv(ovl);377 378 if (op->extra_info_dirty || op->shadow_extra_info_dirty)379 return true;380 }381 }382 383 return false;384}385 386/* wait until no extra_info updates are pending */387static void wait_pending_extra_info_updates(void)388{389 bool updating;390 unsigned long flags;391 unsigned long t;392 int r;393 394 spin_lock_irqsave(&data_lock, flags);395 396 updating = extra_info_update_ongoing();397 398 if (!updating) {399 spin_unlock_irqrestore(&data_lock, flags);400 return;401 }402 403 init_completion(&extra_updated_completion);404 405 spin_unlock_irqrestore(&data_lock, flags);406 407 t = msecs_to_jiffies(500);408 r = wait_for_completion_timeout(&extra_updated_completion, t);409 if (r == 0)410 DSSWARN("timeout in wait_pending_extra_info_updates\n");411}412 413static struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr)414{415 struct omap_dss_device *dssdev;416 417 dssdev = mgr->output;418 if (dssdev == NULL)419 return NULL;420 421 while (dssdev->dst)422 dssdev = dssdev->dst;423 424 if (dssdev->driver)425 return dssdev;426 else427 return NULL;428}429 430static struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl)431{432 return ovl->manager ? dss_mgr_get_device(ovl->manager) : NULL;433}434 435static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)436{437 unsigned long timeout = msecs_to_jiffies(500);438 u32 irq;439 int r;440 441 if (mgr->output == NULL)442 return -ENODEV;443 444 r = dispc_runtime_get();445 if (r)446 return r;447 448 switch (mgr->output->id) {449 case OMAP_DSS_OUTPUT_VENC:450 irq = DISPC_IRQ_EVSYNC_ODD;451 break;452 case OMAP_DSS_OUTPUT_HDMI:453 irq = DISPC_IRQ_EVSYNC_EVEN;454 break;455 default:456 irq = dispc_mgr_get_vsync_irq(mgr->id);457 break;458 }459 460 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);461 462 dispc_runtime_put();463 464 return r;465}466 467static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)468{469 unsigned long timeout = msecs_to_jiffies(500);470 struct mgr_priv_data *mp = get_mgr_priv(mgr);471 u32 irq;472 unsigned long flags;473 int r;474 int i;475 476 spin_lock_irqsave(&data_lock, flags);477 478 if (mgr_manual_update(mgr)) {479 spin_unlock_irqrestore(&data_lock, flags);480 return 0;481 }482 483 if (!mp->enabled) {484 spin_unlock_irqrestore(&data_lock, flags);485 return 0;486 }487 488 spin_unlock_irqrestore(&data_lock, flags);489 490 r = dispc_runtime_get();491 if (r)492 return r;493 494 irq = dispc_mgr_get_vsync_irq(mgr->id);495 496 i = 0;497 while (1) {498 bool shadow_dirty, dirty;499 500 spin_lock_irqsave(&data_lock, flags);501 dirty = mp->info_dirty;502 shadow_dirty = mp->shadow_info_dirty;503 spin_unlock_irqrestore(&data_lock, flags);504 505 if (!dirty && !shadow_dirty) {506 r = 0;507 break;508 }509 510 /* 4 iterations is the worst case:511 * 1 - initial iteration, dirty = true (between VFP and VSYNC)512 * 2 - first VSYNC, dirty = true513 * 3 - dirty = false, shadow_dirty = true514 * 4 - shadow_dirty = false */515 if (i++ == 3) {516 DSSERR("mgr(%d)->wait_for_go() not finishing\n",517 mgr->id);518 r = 0;519 break;520 }521 522 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);523 if (r == -ERESTARTSYS)524 break;525 526 if (r) {527 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);528 break;529 }530 }531 532 dispc_runtime_put();533 534 return r;535}536 537static int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)538{539 unsigned long timeout = msecs_to_jiffies(500);540 struct ovl_priv_data *op;541 struct mgr_priv_data *mp;542 u32 irq;543 unsigned long flags;544 int r;545 int i;546 547 if (!ovl->manager)548 return 0;549 550 mp = get_mgr_priv(ovl->manager);551 552 spin_lock_irqsave(&data_lock, flags);553 554 if (ovl_manual_update(ovl)) {555 spin_unlock_irqrestore(&data_lock, flags);556 return 0;557 }558 559 if (!mp->enabled) {560 spin_unlock_irqrestore(&data_lock, flags);561 return 0;562 }563 564 spin_unlock_irqrestore(&data_lock, flags);565 566 r = dispc_runtime_get();567 if (r)568 return r;569 570 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);571 572 op = get_ovl_priv(ovl);573 i = 0;574 while (1) {575 bool shadow_dirty, dirty;576 577 spin_lock_irqsave(&data_lock, flags);578 dirty = op->info_dirty;579 shadow_dirty = op->shadow_info_dirty;580 spin_unlock_irqrestore(&data_lock, flags);581 582 if (!dirty && !shadow_dirty) {583 r = 0;584 break;585 }586 587 /* 4 iterations is the worst case:588 * 1 - initial iteration, dirty = true (between VFP and VSYNC)589 * 2 - first VSYNC, dirty = true590 * 3 - dirty = false, shadow_dirty = true591 * 4 - shadow_dirty = false */592 if (i++ == 3) {593 DSSERR("ovl(%d)->wait_for_go() not finishing\n",594 ovl->id);595 r = 0;596 break;597 }598 599 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);600 if (r == -ERESTARTSYS)601 break;602 603 if (r) {604 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);605 break;606 }607 }608 609 dispc_runtime_put();610 611 return r;612}613 614static void dss_ovl_write_regs(struct omap_overlay *ovl)615{616 struct ovl_priv_data *op = get_ovl_priv(ovl);617 struct omap_overlay_info *oi;618 bool replication;619 struct mgr_priv_data *mp;620 int r;621 622 DSSDBG("writing ovl %d regs\n", ovl->id);623 624 if (!op->enabled || !op->info_dirty)625 return;626 627 oi = &op->info;628 629 mp = get_mgr_priv(ovl->manager);630 631 replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode);632 633 r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false);634 if (r) {635 /*636 * We can't do much here, as this function can be called from637 * vsync interrupt.638 */639 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);640 641 /* This will leave fifo configurations in a nonoptimal state */642 op->enabled = false;643 dispc_ovl_enable(ovl->id, false);644 return;645 }646 647 op->info_dirty = false;648 if (mp->updating)649 op->shadow_info_dirty = true;650}651 652static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)653{654 struct ovl_priv_data *op = get_ovl_priv(ovl);655 struct mgr_priv_data *mp;656 657 DSSDBG("writing ovl %d regs extra\n", ovl->id);658 659 if (!op->extra_info_dirty)660 return;661 662 /* note: write also when op->enabled == false, so that the ovl gets663 * disabled */664 665 dispc_ovl_enable(ovl->id, op->enabled);666 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);667 668 mp = get_mgr_priv(ovl->manager);669 670 op->extra_info_dirty = false;671 if (mp->updating)672 op->shadow_extra_info_dirty = true;673}674 675static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)676{677 struct mgr_priv_data *mp = get_mgr_priv(mgr);678 struct omap_overlay *ovl;679 680 DSSDBG("writing mgr %d regs\n", mgr->id);681 682 if (!mp->enabled)683 return;684 685 WARN_ON(mp->busy);686 687 /* Commit overlay settings */688 list_for_each_entry(ovl, &mgr->overlays, list) {689 dss_ovl_write_regs(ovl);690 dss_ovl_write_regs_extra(ovl);691 }692 693 if (mp->info_dirty) {694 dispc_mgr_setup(mgr->id, &mp->info);695 696 mp->info_dirty = false;697 if (mp->updating)698 mp->shadow_info_dirty = true;699 }700}701 702static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr)703{704 struct mgr_priv_data *mp = get_mgr_priv(mgr);705 706 DSSDBG("writing mgr %d regs extra\n", mgr->id);707 708 if (!mp->extra_info_dirty)709 return;710 711 dispc_mgr_set_timings(mgr->id, &mp->timings);712 713 /* lcd_config parameters */714 if (dss_mgr_is_lcd(mgr->id))715 dispc_mgr_set_lcd_config(mgr->id, &mp->lcd_config);716 717 mp->extra_info_dirty = false;718 if (mp->updating)719 mp->shadow_extra_info_dirty = true;720}721 722static void dss_write_regs(void)723{724 const int num_mgrs = omap_dss_get_num_overlay_managers();725 int i;726 727 for (i = 0; i < num_mgrs; ++i) {728 struct omap_overlay_manager *mgr;729 struct mgr_priv_data *mp;730 int r;731 732 mgr = omap_dss_get_overlay_manager(i);733 mp = get_mgr_priv(mgr);734 735 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)736 continue;737 738 r = dss_check_settings(mgr);739 if (r) {740 DSSERR("cannot write registers for manager %s: "741 "illegal configuration\n", mgr->name);742 continue;743 }744 745 dss_mgr_write_regs(mgr);746 dss_mgr_write_regs_extra(mgr);747 }748}749 750static void dss_set_go_bits(void)751{752 const int num_mgrs = omap_dss_get_num_overlay_managers();753 int i;754 755 for (i = 0; i < num_mgrs; ++i) {756 struct omap_overlay_manager *mgr;757 struct mgr_priv_data *mp;758 759 mgr = omap_dss_get_overlay_manager(i);760 mp = get_mgr_priv(mgr);761 762 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)763 continue;764 765 if (!need_go(mgr))766 continue;767 768 mp->busy = true;769 770 if (!dss_data.irq_enabled && need_isr())771 dss_register_vsync_isr();772 773 dispc_mgr_go(mgr->id);774 }775 776}777 778static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)779{780 struct omap_overlay *ovl;781 struct mgr_priv_data *mp;782 struct ovl_priv_data *op;783 784 mp = get_mgr_priv(mgr);785 mp->shadow_info_dirty = false;786 mp->shadow_extra_info_dirty = false;787 788 list_for_each_entry(ovl, &mgr->overlays, list) {789 op = get_ovl_priv(ovl);790 op->shadow_info_dirty = false;791 op->shadow_extra_info_dirty = false;792 }793}794 795static int dss_mgr_connect_compat(struct omap_overlay_manager *mgr,796 struct omap_dss_device *dst)797{798 return mgr->set_output(mgr, dst);799}800 801static void dss_mgr_disconnect_compat(struct omap_overlay_manager *mgr,802 struct omap_dss_device *dst)803{804 mgr->unset_output(mgr);805}806 807static void dss_mgr_start_update_compat(struct omap_overlay_manager *mgr)808{809 struct mgr_priv_data *mp = get_mgr_priv(mgr);810 unsigned long flags;811 int r;812 813 spin_lock_irqsave(&data_lock, flags);814 815 WARN_ON(mp->updating);816 817 r = dss_check_settings(mgr);818 if (r) {819 DSSERR("cannot start manual update: illegal configuration\n");820 spin_unlock_irqrestore(&data_lock, flags);821 return;822 }823 824 dss_mgr_write_regs(mgr);825 dss_mgr_write_regs_extra(mgr);826 827 mp->updating = true;828 829 if (!dss_data.irq_enabled && need_isr())830 dss_register_vsync_isr();831 832 dispc_mgr_enable_sync(mgr->id);833 834 spin_unlock_irqrestore(&data_lock, flags);835}836 837static void dss_apply_irq_handler(void *data, u32 mask);838 839static void dss_register_vsync_isr(void)840{841 const int num_mgrs = dss_feat_get_num_mgrs();842 u32 mask;843 int r, i;844 845 mask = 0;846 for (i = 0; i < num_mgrs; ++i)847 mask |= dispc_mgr_get_vsync_irq(i);848 849 for (i = 0; i < num_mgrs; ++i)850 mask |= dispc_mgr_get_framedone_irq(i);851 852 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);853 WARN_ON(r);854 855 dss_data.irq_enabled = true;856}857 858static void dss_unregister_vsync_isr(void)859{860 const int num_mgrs = dss_feat_get_num_mgrs();861 u32 mask;862 int r, i;863 864 mask = 0;865 for (i = 0; i < num_mgrs; ++i)866 mask |= dispc_mgr_get_vsync_irq(i);867 868 for (i = 0; i < num_mgrs; ++i)869 mask |= dispc_mgr_get_framedone_irq(i);870 871 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);872 WARN_ON(r);873 874 dss_data.irq_enabled = false;875}876 877static void dss_apply_irq_handler(void *data, u32 mask)878{879 const int num_mgrs = dss_feat_get_num_mgrs();880 int i;881 bool extra_updating;882 883 spin_lock(&data_lock);884 885 /* clear busy, updating flags, shadow_dirty flags */886 for (i = 0; i < num_mgrs; i++) {887 struct omap_overlay_manager *mgr;888 struct mgr_priv_data *mp;889 890 mgr = omap_dss_get_overlay_manager(i);891 mp = get_mgr_priv(mgr);892 893 if (!mp->enabled)894 continue;895 896 mp->updating = dispc_mgr_is_enabled(i);897 898 if (!mgr_manual_update(mgr)) {899 bool was_busy = mp->busy;900 mp->busy = dispc_mgr_go_busy(i);901 902 if (was_busy && !mp->busy)903 mgr_clear_shadow_dirty(mgr);904 }905 }906 907 dss_write_regs();908 dss_set_go_bits();909 910 extra_updating = extra_info_update_ongoing();911 if (!extra_updating)912 complete_all(&extra_updated_completion);913 914 /* call framedone handlers for manual update displays */915 for (i = 0; i < num_mgrs; i++) {916 struct omap_overlay_manager *mgr;917 struct mgr_priv_data *mp;918 919 mgr = omap_dss_get_overlay_manager(i);920 mp = get_mgr_priv(mgr);921 922 if (!mgr_manual_update(mgr) || !mp->framedone_handler)923 continue;924 925 if (mask & dispc_mgr_get_framedone_irq(i))926 mp->framedone_handler(mp->framedone_handler_data);927 }928 929 if (!need_isr())930 dss_unregister_vsync_isr();931 932 spin_unlock(&data_lock);933}934 935static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)936{937 struct ovl_priv_data *op;938 939 op = get_ovl_priv(ovl);940 941 if (!op->user_info_dirty)942 return;943 944 op->user_info_dirty = false;945 op->info_dirty = true;946 op->info = op->user_info;947}948 949static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)950{951 struct mgr_priv_data *mp;952 953 mp = get_mgr_priv(mgr);954 955 if (!mp->user_info_dirty)956 return;957 958 mp->user_info_dirty = false;959 mp->info_dirty = true;960 mp->info = mp->user_info;961}962 963static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)964{965 unsigned long flags;966 struct omap_overlay *ovl;967 int r;968 969 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);970 971 spin_lock_irqsave(&data_lock, flags);972 973 r = dss_check_settings_apply(mgr);974 if (r) {975 spin_unlock_irqrestore(&data_lock, flags);976 DSSERR("failed to apply settings: illegal configuration.\n");977 return r;978 }979 980 /* Configure overlays */981 list_for_each_entry(ovl, &mgr->overlays, list)982 omap_dss_mgr_apply_ovl(ovl);983 984 /* Configure manager */985 omap_dss_mgr_apply_mgr(mgr);986 987 dss_write_regs();988 dss_set_go_bits();989 990 spin_unlock_irqrestore(&data_lock, flags);991 992 return 0;993}994 995static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable)996{997 struct ovl_priv_data *op;998 999 op = get_ovl_priv(ovl);1000 1001 if (op->enabled == enable)1002 return;1003 1004 op->enabled = enable;1005 op->extra_info_dirty = true;1006}1007 1008static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl,1009 u32 fifo_low, u32 fifo_high)1010{1011 struct ovl_priv_data *op = get_ovl_priv(ovl);1012 1013 if (op->fifo_low == fifo_low && op->fifo_high == fifo_high)1014 return;1015 1016 op->fifo_low = fifo_low;1017 op->fifo_high = fifo_high;1018 op->extra_info_dirty = true;1019}1020 1021static void dss_ovl_setup_fifo(struct omap_overlay *ovl)1022{1023 struct ovl_priv_data *op = get_ovl_priv(ovl);1024 u32 fifo_low, fifo_high;1025 bool use_fifo_merge = false;1026 1027 if (!op->enabled && !op->enabling)1028 return;1029 1030 dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high,1031 use_fifo_merge, ovl_manual_update(ovl));1032 1033 dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);1034}1035 1036static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)1037{1038 struct omap_overlay *ovl;1039 struct mgr_priv_data *mp;1040 1041 mp = get_mgr_priv(mgr);1042 1043 if (!mp->enabled)1044 return;1045 1046 list_for_each_entry(ovl, &mgr->overlays, list)1047 dss_ovl_setup_fifo(ovl);1048}1049 1050static void dss_setup_fifos(void)1051{1052 const int num_mgrs = omap_dss_get_num_overlay_managers();1053 struct omap_overlay_manager *mgr;1054 int i;1055 1056 for (i = 0; i < num_mgrs; ++i) {1057 mgr = omap_dss_get_overlay_manager(i);1058 dss_mgr_setup_fifos(mgr);1059 }1060}1061 1062static int dss_mgr_enable_compat(struct omap_overlay_manager *mgr)1063{1064 struct mgr_priv_data *mp = get_mgr_priv(mgr);1065 unsigned long flags;1066 int r;1067 1068 mutex_lock(&apply_lock);1069 1070 if (mp->enabled)1071 goto out;1072 1073 spin_lock_irqsave(&data_lock, flags);1074 1075 mp->enabled = true;1076 1077 r = dss_check_settings(mgr);1078 if (r) {1079 DSSERR("failed to enable manager %d: check_settings failed\n",1080 mgr->id);1081 goto err;1082 }1083 1084 dss_setup_fifos();1085 1086 dss_write_regs();1087 dss_set_go_bits();1088 1089 if (!mgr_manual_update(mgr))1090 mp->updating = true;1091 1092 if (!dss_data.irq_enabled && need_isr())1093 dss_register_vsync_isr();1094 1095 spin_unlock_irqrestore(&data_lock, flags);1096 1097 if (!mgr_manual_update(mgr))1098 dispc_mgr_enable_sync(mgr->id);1099 1100out:1101 mutex_unlock(&apply_lock);1102 1103 return 0;1104 1105err:1106 mp->enabled = false;1107 spin_unlock_irqrestore(&data_lock, flags);1108 mutex_unlock(&apply_lock);1109 return r;1110}1111 1112static void dss_mgr_disable_compat(struct omap_overlay_manager *mgr)1113{1114 struct mgr_priv_data *mp = get_mgr_priv(mgr);1115 unsigned long flags;1116 1117 mutex_lock(&apply_lock);1118 1119 if (!mp->enabled)1120 goto out;1121 1122 wait_pending_extra_info_updates();1123 1124 if (!mgr_manual_update(mgr))1125 dispc_mgr_disable_sync(mgr->id);1126 1127 spin_lock_irqsave(&data_lock, flags);1128 1129 mp->updating = false;1130 mp->enabled = false;1131 1132 spin_unlock_irqrestore(&data_lock, flags);1133 1134out:1135 mutex_unlock(&apply_lock);1136}1137 1138static int dss_mgr_set_info(struct omap_overlay_manager *mgr,1139 struct omap_overlay_manager_info *info)1140{1141 struct mgr_priv_data *mp = get_mgr_priv(mgr);1142 unsigned long flags;1143 int r;1144 1145 r = dss_mgr_simple_check(mgr, info);1146 if (r)1147 return r;1148 1149 spin_lock_irqsave(&data_lock, flags);1150 1151 mp->user_info = *info;1152 mp->user_info_dirty = true;1153 1154 spin_unlock_irqrestore(&data_lock, flags);1155 1156 return 0;1157}1158 1159static void dss_mgr_get_info(struct omap_overlay_manager *mgr,1160 struct omap_overlay_manager_info *info)1161{1162 struct mgr_priv_data *mp = get_mgr_priv(mgr);1163 unsigned long flags;1164 1165 spin_lock_irqsave(&data_lock, flags);1166 1167 *info = mp->user_info;1168 1169 spin_unlock_irqrestore(&data_lock, flags);1170}1171 1172static int dss_mgr_set_output(struct omap_overlay_manager *mgr,1173 struct omap_dss_device *output)1174{1175 int r;1176 1177 mutex_lock(&apply_lock);1178 1179 if (mgr->output) {1180 DSSERR("manager %s is already connected to an output\n",1181 mgr->name);1182 r = -EINVAL;1183 goto err;1184 }1185 1186 if ((mgr->supported_outputs & output->id) == 0) {1187 DSSERR("output does not support manager %s\n",1188 mgr->name);1189 r = -EINVAL;1190 goto err;1191 }1192 1193 output->manager = mgr;1194 mgr->output = output;1195 1196 mutex_unlock(&apply_lock);1197 1198 return 0;1199err:1200 mutex_unlock(&apply_lock);1201 return r;1202}1203 1204static int dss_mgr_unset_output(struct omap_overlay_manager *mgr)1205{1206 int r;1207 struct mgr_priv_data *mp = get_mgr_priv(mgr);1208 unsigned long flags;1209 1210 mutex_lock(&apply_lock);1211 1212 if (!mgr->output) {1213 DSSERR("failed to unset output, output not set\n");1214 r = -EINVAL;1215 goto err;1216 }1217 1218 spin_lock_irqsave(&data_lock, flags);1219 1220 if (mp->enabled) {1221 DSSERR("output can't be unset when manager is enabled\n");1222 r = -EINVAL;1223 goto err1;1224 }1225 1226 spin_unlock_irqrestore(&data_lock, flags);1227 1228 mgr->output->manager = NULL;1229 mgr->output = NULL;1230 1231 mutex_unlock(&apply_lock);1232 1233 return 0;1234err1:1235 spin_unlock_irqrestore(&data_lock, flags);1236err:1237 mutex_unlock(&apply_lock);1238 1239 return r;1240}1241 1242static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr,1243 const struct omap_video_timings *timings)1244{1245 struct mgr_priv_data *mp = get_mgr_priv(mgr);1246 1247 mp->timings = *timings;1248 mp->extra_info_dirty = true;1249}1250 1251static void dss_mgr_set_timings_compat(struct omap_overlay_manager *mgr,1252 const struct omap_video_timings *timings)1253{1254 unsigned long flags;1255 struct mgr_priv_data *mp = get_mgr_priv(mgr);1256 1257 spin_lock_irqsave(&data_lock, flags);1258 1259 if (mp->updating) {1260 DSSERR("cannot set timings for %s: manager needs to be disabled\n",1261 mgr->name);1262 goto out;1263 }1264 1265 dss_apply_mgr_timings(mgr, timings);1266out:1267 spin_unlock_irqrestore(&data_lock, flags);1268}1269 1270static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr,1271 const struct dss_lcd_mgr_config *config)1272{1273 struct mgr_priv_data *mp = get_mgr_priv(mgr);1274 1275 mp->lcd_config = *config;1276 mp->extra_info_dirty = true;1277}1278 1279static void dss_mgr_set_lcd_config_compat(struct omap_overlay_manager *mgr,1280 const struct dss_lcd_mgr_config *config)1281{1282 unsigned long flags;1283 struct mgr_priv_data *mp = get_mgr_priv(mgr);1284 1285 spin_lock_irqsave(&data_lock, flags);1286 1287 if (mp->enabled) {1288 DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n",1289 mgr->name);1290 goto out;1291 }1292 1293 dss_apply_mgr_lcd_config(mgr, config);1294out:1295 spin_unlock_irqrestore(&data_lock, flags);1296}1297 1298static int dss_ovl_set_info(struct omap_overlay *ovl,1299 struct omap_overlay_info *info)1300{1301 struct ovl_priv_data *op = get_ovl_priv(ovl);1302 unsigned long flags;1303 int r;1304 1305 r = dss_ovl_simple_check(ovl, info);1306 if (r)1307 return r;1308 1309 spin_lock_irqsave(&data_lock, flags);1310 1311 op->user_info = *info;1312 op->user_info_dirty = true;1313 1314 spin_unlock_irqrestore(&data_lock, flags);1315 1316 return 0;1317}1318 1319static void dss_ovl_get_info(struct omap_overlay *ovl,1320 struct omap_overlay_info *info)1321{1322 struct ovl_priv_data *op = get_ovl_priv(ovl);1323 unsigned long flags;1324 1325 spin_lock_irqsave(&data_lock, flags);1326 1327 *info = op->user_info;1328 1329 spin_unlock_irqrestore(&data_lock, flags);1330}1331 1332static int dss_ovl_set_manager(struct omap_overlay *ovl,1333 struct omap_overlay_manager *mgr)1334{1335 struct ovl_priv_data *op = get_ovl_priv(ovl);1336 unsigned long flags;1337 int r;1338 1339 if (!mgr)1340 return -EINVAL;1341 1342 mutex_lock(&apply_lock);1343 1344 if (ovl->manager) {1345 DSSERR("overlay '%s' already has a manager '%s'\n",1346 ovl->name, ovl->manager->name);1347 r = -EINVAL;1348 goto err;1349 }1350 1351 r = dispc_runtime_get();1352 if (r)1353 goto err;1354 1355 spin_lock_irqsave(&data_lock, flags);1356 1357 if (op->enabled) {1358 spin_unlock_irqrestore(&data_lock, flags);1359 DSSERR("overlay has to be disabled to change the manager\n");1360 r = -EINVAL;1361 goto err1;1362 }1363 1364 dispc_ovl_set_channel_out(ovl->id, mgr->id);1365 1366 ovl->manager = mgr;1367 list_add_tail(&ovl->list, &mgr->overlays);1368 1369 spin_unlock_irqrestore(&data_lock, flags);1370 1371 dispc_runtime_put();1372 1373 mutex_unlock(&apply_lock);1374 1375 return 0;1376 1377err1:1378 dispc_runtime_put();1379err:1380 mutex_unlock(&apply_lock);1381 return r;1382}1383 1384static int dss_ovl_unset_manager(struct omap_overlay *ovl)1385{1386 struct ovl_priv_data *op = get_ovl_priv(ovl);1387 unsigned long flags;1388 int r;1389 1390 mutex_lock(&apply_lock);1391 1392 if (!ovl->manager) {1393 DSSERR("failed to detach overlay: manager not set\n");1394 r = -EINVAL;1395 goto err;1396 }1397 1398 spin_lock_irqsave(&data_lock, flags);1399 1400 if (op->enabled) {1401 spin_unlock_irqrestore(&data_lock, flags);1402 DSSERR("overlay has to be disabled to unset the manager\n");1403 r = -EINVAL;1404 goto err;1405 }1406 1407 spin_unlock_irqrestore(&data_lock, flags);1408 1409 /* wait for pending extra_info updates to ensure the ovl is disabled */1410 wait_pending_extra_info_updates();1411 1412 /*1413 * For a manual update display, there is no guarantee that the overlay1414 * is really disabled in HW, we may need an extra update from this1415 * manager before the configurations can go in. Return an error if the1416 * overlay needed an update from the manager.1417 *1418 * TODO: Instead of returning an error, try to do a dummy manager update1419 * here to disable the overlay in hardware. Use the *GATED fields in1420 * the DISPC_CONFIG registers to do a dummy update.1421 */1422 spin_lock_irqsave(&data_lock, flags);1423 1424 if (ovl_manual_update(ovl) && op->extra_info_dirty) {1425 spin_unlock_irqrestore(&data_lock, flags);1426 DSSERR("need an update to change the manager\n");1427 r = -EINVAL;1428 goto err;1429 }1430 1431 ovl->manager = NULL;1432 list_del(&ovl->list);1433 1434 spin_unlock_irqrestore(&data_lock, flags);1435 1436 mutex_unlock(&apply_lock);1437 1438 return 0;1439err:1440 mutex_unlock(&apply_lock);1441 return r;1442}1443 1444static bool dss_ovl_is_enabled(struct omap_overlay *ovl)1445{1446 struct ovl_priv_data *op = get_ovl_priv(ovl);1447 unsigned long flags;1448 bool e;1449 1450 spin_lock_irqsave(&data_lock, flags);1451 1452 e = op->enabled;1453 1454 spin_unlock_irqrestore(&data_lock, flags);1455 1456 return e;1457}1458 1459static int dss_ovl_enable(struct omap_overlay *ovl)1460{1461 struct ovl_priv_data *op = get_ovl_priv(ovl);1462 unsigned long flags;1463 int r;1464 1465 mutex_lock(&apply_lock);1466 1467 if (op->enabled) {1468 r = 0;1469 goto err1;1470 }1471 1472 if (ovl->manager == NULL || ovl->manager->output == NULL) {1473 r = -EINVAL;1474 goto err1;1475 }1476 1477 spin_lock_irqsave(&data_lock, flags);1478 1479 op->enabling = true;1480 1481 r = dss_check_settings(ovl->manager);1482 if (r) {1483 DSSERR("failed to enable overlay %d: check_settings failed\n",1484 ovl->id);1485 goto err2;1486 }1487 1488 dss_setup_fifos();1489 1490 op->enabling = false;1491 dss_apply_ovl_enable(ovl, true);1492 1493 dss_write_regs();1494 dss_set_go_bits();1495 1496 spin_unlock_irqrestore(&data_lock, flags);1497 1498 mutex_unlock(&apply_lock);1499 1500 return 0;1501err2:1502 op->enabling = false;1503 spin_unlock_irqrestore(&data_lock, flags);1504err1:1505 mutex_unlock(&apply_lock);1506 return r;1507}1508 1509static int dss_ovl_disable(struct omap_overlay *ovl)1510{1511 struct ovl_priv_data *op = get_ovl_priv(ovl);1512 unsigned long flags;1513 int r;1514 1515 mutex_lock(&apply_lock);1516 1517 if (!op->enabled) {1518 r = 0;1519 goto err;1520 }1521 1522 if (ovl->manager == NULL || ovl->manager->output == NULL) {1523 r = -EINVAL;1524 goto err;1525 }1526 1527 spin_lock_irqsave(&data_lock, flags);1528 1529 dss_apply_ovl_enable(ovl, false);1530 dss_write_regs();1531 dss_set_go_bits();1532 1533 spin_unlock_irqrestore(&data_lock, flags);1534 1535 mutex_unlock(&apply_lock);1536 1537 return 0;1538 1539err:1540 mutex_unlock(&apply_lock);1541 return r;1542}1543 1544static int dss_mgr_register_framedone_handler_compat(struct omap_overlay_manager *mgr,1545 void (*handler)(void *), void *data)1546{1547 struct mgr_priv_data *mp = get_mgr_priv(mgr);1548 1549 if (mp->framedone_handler)1550 return -EBUSY;1551 1552 mp->framedone_handler = handler;1553 mp->framedone_handler_data = data;1554 1555 return 0;1556}1557 1558static void dss_mgr_unregister_framedone_handler_compat(struct omap_overlay_manager *mgr,1559 void (*handler)(void *), void *data)1560{1561 struct mgr_priv_data *mp = get_mgr_priv(mgr);1562 1563 WARN_ON(mp->framedone_handler != handler ||1564 mp->framedone_handler_data != data);1565 1566 mp->framedone_handler = NULL;1567 mp->framedone_handler_data = NULL;1568}1569 1570static const struct dss_mgr_ops apply_mgr_ops = {1571 .connect = dss_mgr_connect_compat,1572 .disconnect = dss_mgr_disconnect_compat,1573 .start_update = dss_mgr_start_update_compat,1574 .enable = dss_mgr_enable_compat,1575 .disable = dss_mgr_disable_compat,1576 .set_timings = dss_mgr_set_timings_compat,1577 .set_lcd_config = dss_mgr_set_lcd_config_compat,1578 .register_framedone_handler = dss_mgr_register_framedone_handler_compat,1579 .unregister_framedone_handler = dss_mgr_unregister_framedone_handler_compat,1580};1581 1582static int compat_refcnt;1583static DEFINE_MUTEX(compat_init_lock);1584 1585int omapdss_compat_init(void)1586{1587 struct platform_device *pdev = dss_get_core_pdev();1588 int i, r;1589 1590 mutex_lock(&compat_init_lock);1591 1592 if (compat_refcnt++ > 0)1593 goto out;1594 1595 apply_init_priv();1596 1597 dss_init_overlay_managers_sysfs(pdev);1598 dss_init_overlays(pdev);1599 1600 for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) {1601 struct omap_overlay_manager *mgr;1602 1603 mgr = omap_dss_get_overlay_manager(i);1604 1605 mgr->set_output = &dss_mgr_set_output;1606 mgr->unset_output = &dss_mgr_unset_output;1607 mgr->apply = &omap_dss_mgr_apply;1608 mgr->set_manager_info = &dss_mgr_set_info;1609 mgr->get_manager_info = &dss_mgr_get_info;1610 mgr->wait_for_go = &dss_mgr_wait_for_go;1611 mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;1612 mgr->get_device = &dss_mgr_get_device;1613 }1614 1615 for (i = 0; i < omap_dss_get_num_overlays(); i++) {1616 struct omap_overlay *ovl = omap_dss_get_overlay(i);1617 1618 ovl->is_enabled = &dss_ovl_is_enabled;1619 ovl->enable = &dss_ovl_enable;1620 ovl->disable = &dss_ovl_disable;1621 ovl->set_manager = &dss_ovl_set_manager;1622 ovl->unset_manager = &dss_ovl_unset_manager;1623 ovl->set_overlay_info = &dss_ovl_set_info;1624 ovl->get_overlay_info = &dss_ovl_get_info;1625 ovl->wait_for_go = &dss_mgr_wait_for_go_ovl;1626 ovl->get_device = &dss_ovl_get_device;1627 }1628 1629 r = dss_install_mgr_ops(&apply_mgr_ops);1630 if (r)1631 goto err_mgr_ops;1632 1633 r = display_init_sysfs(pdev);1634 if (r)1635 goto err_disp_sysfs;1636 1637 dispc_runtime_get();1638 1639 r = dss_dispc_initialize_irq();1640 if (r)1641 goto err_init_irq;1642 1643 dispc_runtime_put();1644 1645out:1646 mutex_unlock(&compat_init_lock);1647 1648 return 0;1649 1650err_init_irq:1651 dispc_runtime_put();1652 display_uninit_sysfs(pdev);1653 1654err_disp_sysfs:1655 dss_uninstall_mgr_ops();1656 1657err_mgr_ops:1658 dss_uninit_overlay_managers_sysfs(pdev);1659 dss_uninit_overlays(pdev);1660 1661 compat_refcnt--;1662 1663 mutex_unlock(&compat_init_lock);1664 1665 return r;1666}1667EXPORT_SYMBOL(omapdss_compat_init);1668 1669void omapdss_compat_uninit(void)1670{1671 struct platform_device *pdev = dss_get_core_pdev();1672 1673 mutex_lock(&compat_init_lock);1674 1675 if (--compat_refcnt > 0)1676 goto out;1677 1678 dss_dispc_uninitialize_irq();1679 1680 display_uninit_sysfs(pdev);1681 1682 dss_uninstall_mgr_ops();1683 1684 dss_uninit_overlay_managers_sysfs(pdev);1685 dss_uninit_overlays(pdev);1686out:1687 mutex_unlock(&compat_init_lock);1688}1689EXPORT_SYMBOL(omapdss_compat_uninit);1690