18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2013 Red Hat 48c2ecf20Sopenharmony_ci * Author: Rob Clark <robdclark@gmail.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "msm_drv.h" 98c2ecf20Sopenharmony_ci#include "mdp_kms.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistruct mdp_irq_wait { 138c2ecf20Sopenharmony_ci struct mdp_irq irq; 148c2ecf20Sopenharmony_ci int count; 158c2ecf20Sopenharmony_ci}; 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(wait_event); 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(list_lock); 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic void update_irq(struct mdp_kms *mdp_kms) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci struct mdp_irq *irq; 248c2ecf20Sopenharmony_ci uint32_t irqmask = mdp_kms->vblank_mask; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci assert_spin_locked(&list_lock); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci list_for_each_entry(irq, &mdp_kms->irq_list, node) 298c2ecf20Sopenharmony_ci irqmask |= irq->irqmask; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci mdp_kms->funcs->set_irqmask(mdp_kms, irqmask, mdp_kms->cur_irq_mask); 328c2ecf20Sopenharmony_ci mdp_kms->cur_irq_mask = irqmask; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* if an mdp_irq's irqmask has changed, such as when mdp5 crtc<->encoder 368c2ecf20Sopenharmony_ci * link changes, this must be called to figure out the new global irqmask 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_civoid mdp_irq_update(struct mdp_kms *mdp_kms) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci unsigned long flags; 418c2ecf20Sopenharmony_ci spin_lock_irqsave(&list_lock, flags); 428c2ecf20Sopenharmony_ci update_irq(mdp_kms); 438c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&list_lock, flags); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_civoid mdp_dispatch_irqs(struct mdp_kms *mdp_kms, uint32_t status) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct mdp_irq *handler, *n; 498c2ecf20Sopenharmony_ci unsigned long flags; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci spin_lock_irqsave(&list_lock, flags); 528c2ecf20Sopenharmony_ci mdp_kms->in_irq = true; 538c2ecf20Sopenharmony_ci list_for_each_entry_safe(handler, n, &mdp_kms->irq_list, node) { 548c2ecf20Sopenharmony_ci if (handler->irqmask & status) { 558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&list_lock, flags); 568c2ecf20Sopenharmony_ci handler->irq(handler, handler->irqmask & status); 578c2ecf20Sopenharmony_ci spin_lock_irqsave(&list_lock, flags); 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci mdp_kms->in_irq = false; 618c2ecf20Sopenharmony_ci update_irq(mdp_kms); 628c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&list_lock, flags); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_civoid mdp_update_vblank_mask(struct mdp_kms *mdp_kms, uint32_t mask, bool enable) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci unsigned long flags; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci spin_lock_irqsave(&list_lock, flags); 718c2ecf20Sopenharmony_ci if (enable) 728c2ecf20Sopenharmony_ci mdp_kms->vblank_mask |= mask; 738c2ecf20Sopenharmony_ci else 748c2ecf20Sopenharmony_ci mdp_kms->vblank_mask &= ~mask; 758c2ecf20Sopenharmony_ci update_irq(mdp_kms); 768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&list_lock, flags); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic void wait_irq(struct mdp_irq *irq, uint32_t irqstatus) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct mdp_irq_wait *wait = 828c2ecf20Sopenharmony_ci container_of(irq, struct mdp_irq_wait, irq); 838c2ecf20Sopenharmony_ci wait->count--; 848c2ecf20Sopenharmony_ci wake_up_all(&wait_event); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_civoid mdp_irq_wait(struct mdp_kms *mdp_kms, uint32_t irqmask) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct mdp_irq_wait wait = { 908c2ecf20Sopenharmony_ci .irq = { 918c2ecf20Sopenharmony_ci .irq = wait_irq, 928c2ecf20Sopenharmony_ci .irqmask = irqmask, 938c2ecf20Sopenharmony_ci }, 948c2ecf20Sopenharmony_ci .count = 1, 958c2ecf20Sopenharmony_ci }; 968c2ecf20Sopenharmony_ci mdp_irq_register(mdp_kms, &wait.irq); 978c2ecf20Sopenharmony_ci wait_event_timeout(wait_event, (wait.count <= 0), 988c2ecf20Sopenharmony_ci msecs_to_jiffies(100)); 998c2ecf20Sopenharmony_ci mdp_irq_unregister(mdp_kms, &wait.irq); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_civoid mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci unsigned long flags; 1058c2ecf20Sopenharmony_ci bool needs_update = false; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci spin_lock_irqsave(&list_lock, flags); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (!irq->registered) { 1108c2ecf20Sopenharmony_ci irq->registered = true; 1118c2ecf20Sopenharmony_ci list_add(&irq->node, &mdp_kms->irq_list); 1128c2ecf20Sopenharmony_ci needs_update = !mdp_kms->in_irq; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&list_lock, flags); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (needs_update) 1188c2ecf20Sopenharmony_ci mdp_irq_update(mdp_kms); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_civoid mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci unsigned long flags; 1248c2ecf20Sopenharmony_ci bool needs_update = false; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci spin_lock_irqsave(&list_lock, flags); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (irq->registered) { 1298c2ecf20Sopenharmony_ci irq->registered = false; 1308c2ecf20Sopenharmony_ci list_del(&irq->node); 1318c2ecf20Sopenharmony_ci needs_update = !mdp_kms->in_irq; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&list_lock, flags); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (needs_update) 1378c2ecf20Sopenharmony_ci mdp_irq_update(mdp_kms); 1388c2ecf20Sopenharmony_ci} 139