139 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2013 Red Hat4 * Author: Rob Clark <robdclark@gmail.com>5 */6 7 8#include "msm_drv.h"9#include "mdp_kms.h"10 11 12struct mdp_irq_wait {13 struct mdp_irq irq;14 int count;15};16 17static DECLARE_WAIT_QUEUE_HEAD(wait_event);18 19static DEFINE_SPINLOCK(list_lock);20 21static void update_irq(struct mdp_kms *mdp_kms)22{23 struct mdp_irq *irq;24 uint32_t irqmask = mdp_kms->vblank_mask;25 26 assert_spin_locked(&list_lock);27 28 list_for_each_entry(irq, &mdp_kms->irq_list, node)29 irqmask |= irq->irqmask;30 31 mdp_kms->funcs->set_irqmask(mdp_kms, irqmask, mdp_kms->cur_irq_mask);32 mdp_kms->cur_irq_mask = irqmask;33}34 35/* if an mdp_irq's irqmask has changed, such as when mdp5 crtc<->encoder36 * link changes, this must be called to figure out the new global irqmask37 */38void mdp_irq_update(struct mdp_kms *mdp_kms)39{40 unsigned long flags;41 spin_lock_irqsave(&list_lock, flags);42 update_irq(mdp_kms);43 spin_unlock_irqrestore(&list_lock, flags);44}45 46void mdp_dispatch_irqs(struct mdp_kms *mdp_kms, uint32_t status)47{48 struct mdp_irq *handler, *n;49 unsigned long flags;50 51 spin_lock_irqsave(&list_lock, flags);52 mdp_kms->in_irq = true;53 list_for_each_entry_safe(handler, n, &mdp_kms->irq_list, node) {54 if (handler->irqmask & status) {55 spin_unlock_irqrestore(&list_lock, flags);56 handler->irq(handler, handler->irqmask & status);57 spin_lock_irqsave(&list_lock, flags);58 }59 }60 mdp_kms->in_irq = false;61 update_irq(mdp_kms);62 spin_unlock_irqrestore(&list_lock, flags);63 64}65 66void mdp_update_vblank_mask(struct mdp_kms *mdp_kms, uint32_t mask, bool enable)67{68 unsigned long flags;69 70 spin_lock_irqsave(&list_lock, flags);71 if (enable)72 mdp_kms->vblank_mask |= mask;73 else74 mdp_kms->vblank_mask &= ~mask;75 update_irq(mdp_kms);76 spin_unlock_irqrestore(&list_lock, flags);77}78 79static void wait_irq(struct mdp_irq *irq, uint32_t irqstatus)80{81 struct mdp_irq_wait *wait =82 container_of(irq, struct mdp_irq_wait, irq);83 wait->count--;84 wake_up_all(&wait_event);85}86 87void mdp_irq_wait(struct mdp_kms *mdp_kms, uint32_t irqmask)88{89 struct mdp_irq_wait wait = {90 .irq = {91 .irq = wait_irq,92 .irqmask = irqmask,93 },94 .count = 1,95 };96 mdp_irq_register(mdp_kms, &wait.irq);97 wait_event_timeout(wait_event, (wait.count <= 0),98 msecs_to_jiffies(100));99 mdp_irq_unregister(mdp_kms, &wait.irq);100}101 102void mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq)103{104 unsigned long flags;105 bool needs_update = false;106 107 spin_lock_irqsave(&list_lock, flags);108 109 if (!irq->registered) {110 irq->registered = true;111 list_add(&irq->node, &mdp_kms->irq_list);112 needs_update = !mdp_kms->in_irq;113 }114 115 spin_unlock_irqrestore(&list_lock, flags);116 117 if (needs_update)118 mdp_irq_update(mdp_kms);119}120 121void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq)122{123 unsigned long flags;124 bool needs_update = false;125 126 spin_lock_irqsave(&list_lock, flags);127 128 if (irq->registered) {129 irq->registered = false;130 list_del(&irq->node);131 needs_update = !mdp_kms->in_irq;132 }133 134 spin_unlock_irqrestore(&list_lock, flags);135 136 if (needs_update)137 mdp_irq_update(mdp_kms);138}139