xref: /openbmc/linux/drivers/gpu/host1x/hw/intr_hw.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
19952f691SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
27ede0b0bSTerje Bergstrom /*
37ede0b0bSTerje Bergstrom  * Tegra host1x Interrupt Management
47ede0b0bSTerje Bergstrom  *
57ede0b0bSTerje Bergstrom  * Copyright (C) 2010 Google, Inc.
67ede0b0bSTerje Bergstrom  * Copyright (c) 2010-2013, NVIDIA Corporation.
77ede0b0bSTerje Bergstrom  */
87ede0b0bSTerje Bergstrom 
97ede0b0bSTerje Bergstrom #include <linux/interrupt.h>
107ede0b0bSTerje Bergstrom #include <linux/irq.h>
117ede0b0bSTerje Bergstrom #include <linux/io.h>
127ede0b0bSTerje Bergstrom 
13fc3be3e8SThierry Reding #include "../intr.h"
14fc3be3e8SThierry Reding #include "../dev.h"
157ede0b0bSTerje Bergstrom 
syncpt_thresh_isr(int irq,void * dev_id)167ede0b0bSTerje Bergstrom static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id)
177ede0b0bSTerje Bergstrom {
187ede0b0bSTerje Bergstrom 	struct host1x *host = dev_id;
197ede0b0bSTerje Bergstrom 	unsigned long reg;
2014c95fc8SThierry Reding 	unsigned int i, id;
217ede0b0bSTerje Bergstrom 
2222bbd5d9SStephen Warren 	for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); i++) {
237ede0b0bSTerje Bergstrom 		reg = host1x_sync_readl(host,
247ede0b0bSTerje Bergstrom 			HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i));
25*625d4ffbSMikko Perttunen 
26*625d4ffbSMikko Perttunen 		host1x_sync_writel(host, reg,
27*625d4ffbSMikko Perttunen 			HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(i));
28*625d4ffbSMikko Perttunen 		host1x_sync_writel(host, reg,
29*625d4ffbSMikko Perttunen 			HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i));
30*625d4ffbSMikko Perttunen 
31*625d4ffbSMikko Perttunen 		for_each_set_bit(id, &reg, 32)
32*625d4ffbSMikko Perttunen 			host1x_intr_handle_interrupt(host, i * 32 + id);
337ede0b0bSTerje Bergstrom 	}
347ede0b0bSTerje Bergstrom 
357ede0b0bSTerje Bergstrom 	return IRQ_HANDLED;
367ede0b0bSTerje Bergstrom }
377ede0b0bSTerje Bergstrom 
host1x_intr_disable_all_syncpt_intrs(struct host1x * host)38*625d4ffbSMikko Perttunen static void host1x_intr_disable_all_syncpt_intrs(struct host1x *host)
397ede0b0bSTerje Bergstrom {
4014c95fc8SThierry Reding 	unsigned int i;
417ede0b0bSTerje Bergstrom 
4222bbd5d9SStephen Warren 	for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); ++i) {
437ede0b0bSTerje Bergstrom 		host1x_sync_writel(host, 0xffffffffu,
447ede0b0bSTerje Bergstrom 			HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(i));
457ede0b0bSTerje Bergstrom 		host1x_sync_writel(host, 0xffffffffu,
467ede0b0bSTerje Bergstrom 			HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i));
477ede0b0bSTerje Bergstrom 	}
487ede0b0bSTerje Bergstrom }
497ede0b0bSTerje Bergstrom 
intr_hw_init(struct host1x * host,u32 cpm)50f1b53c4eSMikko Perttunen static void intr_hw_init(struct host1x *host, u32 cpm)
51f1b53c4eSMikko Perttunen {
52f1b53c4eSMikko Perttunen #if HOST1X_HW < 6
53f1b53c4eSMikko Perttunen 	/* disable the ip_busy_timeout. this prevents write drops */
54f1b53c4eSMikko Perttunen 	host1x_sync_writel(host, 0, HOST1X_SYNC_IP_BUSY_TIMEOUT);
55f1b53c4eSMikko Perttunen 
56f1b53c4eSMikko Perttunen 	/*
57f1b53c4eSMikko Perttunen 	 * increase the auto-ack timout to the maximum value. 2d will hang
58f1b53c4eSMikko Perttunen 	 * otherwise on Tegra2.
59f1b53c4eSMikko Perttunen 	 */
60f1b53c4eSMikko Perttunen 	host1x_sync_writel(host, 0xff, HOST1X_SYNC_CTXSW_TIMEOUT_CFG);
61f1b53c4eSMikko Perttunen 
62f1b53c4eSMikko Perttunen 	/* update host clocks per usec */
63f1b53c4eSMikko Perttunen 	host1x_sync_writel(host, cpm, HOST1X_SYNC_USEC_CLK);
64f1b53c4eSMikko Perttunen #endif
657afd1194SMikko Perttunen #if HOST1X_HW >= 8
667afd1194SMikko Perttunen 	u32 id;
677afd1194SMikko Perttunen 
687afd1194SMikko Perttunen 	/*
697afd1194SMikko Perttunen 	 * Program threshold interrupt destination among 8 lines per VM,
707afd1194SMikko Perttunen 	 * per syncpoint. For now, just direct all to the first interrupt
717afd1194SMikko Perttunen 	 * line.
727afd1194SMikko Perttunen 	 */
737afd1194SMikko Perttunen 	for (id = 0; id < host->info->nb_pts; id++)
747afd1194SMikko Perttunen 		host1x_sync_writel(host, 0, HOST1X_SYNC_SYNCPT_INTR_DEST(id));
757afd1194SMikko Perttunen #endif
76f1b53c4eSMikko Perttunen }
77f1b53c4eSMikko Perttunen 
780b8070d1SThierry Reding static int
host1x_intr_init_host_sync(struct host1x * host,u32 cpm)79*625d4ffbSMikko Perttunen host1x_intr_init_host_sync(struct host1x *host, u32 cpm)
807ede0b0bSTerje Bergstrom {
8114c95fc8SThierry Reding 	int err;
827ede0b0bSTerje Bergstrom 
837ede0b0bSTerje Bergstrom 	host1x_hw_intr_disable_all_syncpt_intrs(host);
847ede0b0bSTerje Bergstrom 
85*625d4ffbSMikko Perttunen 	err = devm_request_irq(host->dev, host->syncpt_irq,
867ede0b0bSTerje Bergstrom 			       syncpt_thresh_isr, IRQF_SHARED,
877ede0b0bSTerje Bergstrom 			       "host1x_syncpt", host);
88*625d4ffbSMikko Perttunen 	if (err < 0)
897ede0b0bSTerje Bergstrom 		return err;
907ede0b0bSTerje Bergstrom 
91f1b53c4eSMikko Perttunen 	intr_hw_init(host, cpm);
927ede0b0bSTerje Bergstrom 
937ede0b0bSTerje Bergstrom 	return 0;
947ede0b0bSTerje Bergstrom }
957ede0b0bSTerje Bergstrom 
host1x_intr_set_syncpt_threshold(struct host1x * host,unsigned int id,u32 thresh)96*625d4ffbSMikko Perttunen static void host1x_intr_set_syncpt_threshold(struct host1x *host,
975c0d8d38SThierry Reding 					      unsigned int id,
985c0d8d38SThierry Reding 					      u32 thresh)
997ede0b0bSTerje Bergstrom {
1007ede0b0bSTerje Bergstrom 	host1x_sync_writel(host, thresh, HOST1X_SYNC_SYNCPT_INT_THRESH(id));
1017ede0b0bSTerje Bergstrom }
1027ede0b0bSTerje Bergstrom 
host1x_intr_enable_syncpt_intr(struct host1x * host,unsigned int id)103*625d4ffbSMikko Perttunen static void host1x_intr_enable_syncpt_intr(struct host1x *host,
1045c0d8d38SThierry Reding 					    unsigned int id)
1057ede0b0bSTerje Bergstrom {
1064ac45eb8SMikko Perttunen 	host1x_sync_writel(host, BIT(id % 32),
1074ac45eb8SMikko Perttunen 		HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(id / 32));
1087ede0b0bSTerje Bergstrom }
1097ede0b0bSTerje Bergstrom 
host1x_intr_disable_syncpt_intr(struct host1x * host,unsigned int id)110*625d4ffbSMikko Perttunen static void host1x_intr_disable_syncpt_intr(struct host1x *host,
1115c0d8d38SThierry Reding 					     unsigned int id)
1127ede0b0bSTerje Bergstrom {
1134ac45eb8SMikko Perttunen 	host1x_sync_writel(host, BIT(id % 32),
1144ac45eb8SMikko Perttunen 		HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(id / 32));
1154ac45eb8SMikko Perttunen 	host1x_sync_writel(host, BIT(id % 32),
1164ac45eb8SMikko Perttunen 		HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(id / 32));
1177ede0b0bSTerje Bergstrom }
1187ede0b0bSTerje Bergstrom 
1197ede0b0bSTerje Bergstrom static const struct host1x_intr_ops host1x_intr_ops = {
120*625d4ffbSMikko Perttunen 	.init_host_sync = host1x_intr_init_host_sync,
121*625d4ffbSMikko Perttunen 	.set_syncpt_threshold = host1x_intr_set_syncpt_threshold,
122*625d4ffbSMikko Perttunen 	.enable_syncpt_intr = host1x_intr_enable_syncpt_intr,
123*625d4ffbSMikko Perttunen 	.disable_syncpt_intr = host1x_intr_disable_syncpt_intr,
124*625d4ffbSMikko Perttunen 	.disable_all_syncpt_intrs = host1x_intr_disable_all_syncpt_intrs,
1257ede0b0bSTerje Bergstrom };
126