xref: /linux/drivers/gpu/host1x/intr.c (revision de848da12f752170c2ebe114804a985314fd5a6a)
19952f691SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
27ede0b0bSTerje Bergstrom /*
37ede0b0bSTerje Bergstrom  * Tegra host1x Interrupt Management
47ede0b0bSTerje Bergstrom  *
5625d4ffbSMikko Perttunen  * Copyright (c) 2010-2021, NVIDIA Corporation.
67ede0b0bSTerje Bergstrom  */
77ede0b0bSTerje Bergstrom 
87ede0b0bSTerje Bergstrom #include <linux/clk.h>
9*4c27ac45SMikko Perttunen #include <linux/interrupt.h>
107ede0b0bSTerje Bergstrom #include "dev.h"
11687db220SMikko Perttunen #include "fence.h"
127ede0b0bSTerje Bergstrom #include "intr.h"
137ede0b0bSTerje Bergstrom 
14625d4ffbSMikko Perttunen static void host1x_intr_add_fence_to_list(struct host1x_fence_list *list,
15625d4ffbSMikko Perttunen 					  struct host1x_syncpt_fence *fence)
167ede0b0bSTerje Bergstrom {
17625d4ffbSMikko Perttunen 	struct host1x_syncpt_fence *fence_in_list;
18625d4ffbSMikko Perttunen 
19625d4ffbSMikko Perttunen 	list_for_each_entry_reverse(fence_in_list, &list->list, list) {
20625d4ffbSMikko Perttunen 		if ((s32)(fence_in_list->threshold - fence->threshold) <= 0) {
21625d4ffbSMikko Perttunen 			/* Fence in list is before us, we can insert here */
22625d4ffbSMikko Perttunen 			list_add(&fence->list, &fence_in_list->list);
23625d4ffbSMikko Perttunen 			return;
24625d4ffbSMikko Perttunen 		}
257ede0b0bSTerje Bergstrom 	}
267ede0b0bSTerje Bergstrom 
27625d4ffbSMikko Perttunen 	/* Add as first in list */
28625d4ffbSMikko Perttunen 	list_add(&fence->list, &list->list);
29625d4ffbSMikko Perttunen }
307ede0b0bSTerje Bergstrom 
31625d4ffbSMikko Perttunen static void host1x_intr_update_hw_state(struct host1x *host, struct host1x_syncpt *sp)
32625d4ffbSMikko Perttunen {
33625d4ffbSMikko Perttunen 	struct host1x_syncpt_fence *fence;
34625d4ffbSMikko Perttunen 
35625d4ffbSMikko Perttunen 	if (!list_empty(&sp->fences.list)) {
36625d4ffbSMikko Perttunen 		fence = list_first_entry(&sp->fences.list, struct host1x_syncpt_fence, list);
37625d4ffbSMikko Perttunen 
38625d4ffbSMikko Perttunen 		host1x_hw_intr_set_syncpt_threshold(host, sp->id, fence->threshold);
39625d4ffbSMikko Perttunen 		host1x_hw_intr_enable_syncpt_intr(host, sp->id);
40625d4ffbSMikko Perttunen 	} else {
41625d4ffbSMikko Perttunen 		host1x_hw_intr_disable_syncpt_intr(host, sp->id);
42625d4ffbSMikko Perttunen 	}
43625d4ffbSMikko Perttunen }
44625d4ffbSMikko Perttunen 
45625d4ffbSMikko Perttunen void host1x_intr_add_fence_locked(struct host1x *host, struct host1x_syncpt_fence *fence)
46625d4ffbSMikko Perttunen {
47625d4ffbSMikko Perttunen 	struct host1x_fence_list *fence_list = &fence->sp->fences;
48625d4ffbSMikko Perttunen 
49625d4ffbSMikko Perttunen 	INIT_LIST_HEAD(&fence->list);
50625d4ffbSMikko Perttunen 
51625d4ffbSMikko Perttunen 	host1x_intr_add_fence_to_list(fence_list, fence);
52625d4ffbSMikko Perttunen 	host1x_intr_update_hw_state(host, fence->sp);
53625d4ffbSMikko Perttunen }
54625d4ffbSMikko Perttunen 
55625d4ffbSMikko Perttunen bool host1x_intr_remove_fence(struct host1x *host, struct host1x_syncpt_fence *fence)
56625d4ffbSMikko Perttunen {
57625d4ffbSMikko Perttunen 	struct host1x_fence_list *fence_list = &fence->sp->fences;
58625d4ffbSMikko Perttunen 	unsigned long irqflags;
59625d4ffbSMikko Perttunen 
60625d4ffbSMikko Perttunen 	spin_lock_irqsave(&fence_list->lock, irqflags);
61625d4ffbSMikko Perttunen 
62625d4ffbSMikko Perttunen 	if (list_empty(&fence->list)) {
63625d4ffbSMikko Perttunen 		spin_unlock_irqrestore(&fence_list->lock, irqflags);
647ede0b0bSTerje Bergstrom 		return false;
657ede0b0bSTerje Bergstrom 	}
667ede0b0bSTerje Bergstrom 
67625d4ffbSMikko Perttunen 	list_del_init(&fence->list);
68625d4ffbSMikko Perttunen 	host1x_intr_update_hw_state(host, fence->sp);
69625d4ffbSMikko Perttunen 
70625d4ffbSMikko Perttunen 	spin_unlock_irqrestore(&fence_list->lock, irqflags);
71625d4ffbSMikko Perttunen 
727ede0b0bSTerje Bergstrom 	return true;
737ede0b0bSTerje Bergstrom }
747ede0b0bSTerje Bergstrom 
75625d4ffbSMikko Perttunen void host1x_intr_handle_interrupt(struct host1x *host, unsigned int id)
767ede0b0bSTerje Bergstrom {
77625d4ffbSMikko Perttunen 	struct host1x_syncpt *sp = &host->syncpt[id];
78625d4ffbSMikko Perttunen 	struct host1x_syncpt_fence *fence, *tmp;
79625d4ffbSMikko Perttunen 	unsigned int value;
807ede0b0bSTerje Bergstrom 
81625d4ffbSMikko Perttunen 	value = host1x_syncpt_load(sp);
82625d4ffbSMikko Perttunen 
83625d4ffbSMikko Perttunen 	spin_lock(&sp->fences.lock);
84625d4ffbSMikko Perttunen 
85625d4ffbSMikko Perttunen 	list_for_each_entry_safe(fence, tmp, &sp->fences.list, list) {
86625d4ffbSMikko Perttunen 		if (((value - fence->threshold) & 0x80000000U) != 0U) {
87625d4ffbSMikko Perttunen 			/* Fence is not yet expired, we are done */
887ede0b0bSTerje Bergstrom 			break;
896579324aSTerje Bergstrom 		}
906579324aSTerje Bergstrom 
91625d4ffbSMikko Perttunen 		list_del_init(&fence->list);
92625d4ffbSMikko Perttunen 		host1x_fence_signal(fence);
937ede0b0bSTerje Bergstrom 	}
947ede0b0bSTerje Bergstrom 
95625d4ffbSMikko Perttunen 	/* Re-enable interrupt if necessary */
96625d4ffbSMikko Perttunen 	host1x_intr_update_hw_state(host, sp);
977ede0b0bSTerje Bergstrom 
98625d4ffbSMikko Perttunen 	spin_unlock(&sp->fences.lock);
997ede0b0bSTerje Bergstrom }
1007ede0b0bSTerje Bergstrom 
101625d4ffbSMikko Perttunen int host1x_intr_init(struct host1x *host)
1027ede0b0bSTerje Bergstrom {
103*4c27ac45SMikko Perttunen 	struct host1x_intr_irq_data *irq_data;
1047ede0b0bSTerje Bergstrom 	unsigned int id;
105*4c27ac45SMikko Perttunen 	int i, err;
1067ede0b0bSTerje Bergstrom 
1077ede0b0bSTerje Bergstrom 	mutex_init(&host->intr_mutex);
1087ede0b0bSTerje Bergstrom 
109625d4ffbSMikko Perttunen 	for (id = 0; id < host1x_syncpt_nb_pts(host); ++id) {
110625d4ffbSMikko Perttunen 		struct host1x_syncpt *syncpt = &host->syncpt[id];
1117ede0b0bSTerje Bergstrom 
112625d4ffbSMikko Perttunen 		spin_lock_init(&syncpt->fences.lock);
113625d4ffbSMikko Perttunen 		INIT_LIST_HEAD(&syncpt->fences.list);
1147ede0b0bSTerje Bergstrom 	}
1157ede0b0bSTerje Bergstrom 
116*4c27ac45SMikko Perttunen 	irq_data = devm_kcalloc(host->dev, host->num_syncpt_irqs, sizeof(irq_data[0]), GFP_KERNEL);
117*4c27ac45SMikko Perttunen 	if (!irq_data)
118*4c27ac45SMikko Perttunen 		return -ENOMEM;
119*4c27ac45SMikko Perttunen 
120*4c27ac45SMikko Perttunen 	host1x_hw_intr_disable_all_syncpt_intrs(host);
121*4c27ac45SMikko Perttunen 
122*4c27ac45SMikko Perttunen 	for (i = 0; i < host->num_syncpt_irqs; i++) {
123*4c27ac45SMikko Perttunen 		irq_data[i].host = host;
124*4c27ac45SMikko Perttunen 		irq_data[i].offset = i;
125*4c27ac45SMikko Perttunen 
126*4c27ac45SMikko Perttunen 		err = devm_request_irq(host->dev, host->syncpt_irqs[i],
127*4c27ac45SMikko Perttunen 				       host->intr_op->isr, IRQF_SHARED,
128*4c27ac45SMikko Perttunen 				       "host1x_syncpt", &irq_data[i]);
129*4c27ac45SMikko Perttunen 		if (err < 0)
130*4c27ac45SMikko Perttunen 			return err;
131*4c27ac45SMikko Perttunen 	}
132*4c27ac45SMikko Perttunen 
1337ede0b0bSTerje Bergstrom 	return 0;
1347ede0b0bSTerje Bergstrom }
1357ede0b0bSTerje Bergstrom 
1367ede0b0bSTerje Bergstrom void host1x_intr_deinit(struct host1x *host)
1377ede0b0bSTerje Bergstrom {
1387ede0b0bSTerje Bergstrom }
1397ede0b0bSTerje Bergstrom 
1407ede0b0bSTerje Bergstrom void host1x_intr_start(struct host1x *host)
1417ede0b0bSTerje Bergstrom {
1427ede0b0bSTerje Bergstrom 	u32 hz = clk_get_rate(host->clk);
1437ede0b0bSTerje Bergstrom 	int err;
1447ede0b0bSTerje Bergstrom 
1457ede0b0bSTerje Bergstrom 	mutex_lock(&host->intr_mutex);
146625d4ffbSMikko Perttunen 	err = host1x_hw_intr_init_host_sync(host, DIV_ROUND_UP(hz, 1000000));
1477ede0b0bSTerje Bergstrom 	if (err) {
1487ede0b0bSTerje Bergstrom 		mutex_unlock(&host->intr_mutex);
1497ede0b0bSTerje Bergstrom 		return;
1507ede0b0bSTerje Bergstrom 	}
1517ede0b0bSTerje Bergstrom 	mutex_unlock(&host->intr_mutex);
1527ede0b0bSTerje Bergstrom }
1537ede0b0bSTerje Bergstrom 
1547ede0b0bSTerje Bergstrom void host1x_intr_stop(struct host1x *host)
1557ede0b0bSTerje Bergstrom {
1567ede0b0bSTerje Bergstrom 	host1x_hw_intr_disable_all_syncpt_intrs(host);
1577ede0b0bSTerje Bergstrom }
158