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