Commit | Line | Data |
---|---|---|
7ede0b0b TB |
1 | /* |
2 | * Tegra host1x Interrupt Management | |
3 | * | |
4 | * Copyright (C) 2010 Google, Inc. | |
5 | * Copyright (c) 2010-2013, NVIDIA Corporation. | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms and conditions of the GNU General Public License, | |
9 | * version 2, as published by the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope it will be useful, but WITHOUT | |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
14 | * more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
20 | #include <linux/interrupt.h> | |
21 | #include <linux/irq.h> | |
22 | #include <linux/io.h> | |
23 | #include <asm/mach/irq.h> | |
24 | ||
fc3be3e8 TR |
25 | #include "../intr.h" |
26 | #include "../dev.h" | |
7ede0b0b TB |
27 | |
28 | /* | |
29 | * Sync point threshold interrupt service function | |
30 | * Handles sync point threshold triggers, in interrupt context | |
31 | */ | |
32 | static void host1x_intr_syncpt_handle(struct host1x_syncpt *syncpt) | |
33 | { | |
34 | unsigned int id = syncpt->id; | |
35 | struct host1x *host = syncpt->host; | |
36 | ||
37 | host1x_sync_writel(host, BIT_MASK(id), | |
38 | HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(BIT_WORD(id))); | |
39 | host1x_sync_writel(host, BIT_MASK(id), | |
40 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(BIT_WORD(id))); | |
41 | ||
42 | queue_work(host->intr_wq, &syncpt->intr.work); | |
43 | } | |
44 | ||
45 | static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id) | |
46 | { | |
47 | struct host1x *host = dev_id; | |
48 | unsigned long reg; | |
49 | int i, id; | |
50 | ||
51 | for (i = 0; i <= BIT_WORD(host->info->nb_pts); i++) { | |
52 | reg = host1x_sync_readl(host, | |
53 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i)); | |
54 | for_each_set_bit(id, ®, BITS_PER_LONG) { | |
55 | struct host1x_syncpt *syncpt = | |
56 | host->syncpt + (i * BITS_PER_LONG + id); | |
57 | host1x_intr_syncpt_handle(syncpt); | |
58 | } | |
59 | } | |
60 | ||
61 | return IRQ_HANDLED; | |
62 | } | |
63 | ||
64 | static void _host1x_intr_disable_all_syncpt_intrs(struct host1x *host) | |
65 | { | |
66 | u32 i; | |
67 | ||
68 | for (i = 0; i <= BIT_WORD(host->info->nb_pts); ++i) { | |
69 | host1x_sync_writel(host, 0xffffffffu, | |
70 | HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(i)); | |
71 | host1x_sync_writel(host, 0xffffffffu, | |
72 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i)); | |
73 | } | |
74 | } | |
75 | ||
76 | static int _host1x_intr_init_host_sync(struct host1x *host, u32 cpm, | |
77 | void (*syncpt_thresh_work)(struct work_struct *)) | |
78 | { | |
79 | int i, err; | |
80 | ||
81 | host1x_hw_intr_disable_all_syncpt_intrs(host); | |
82 | ||
83 | for (i = 0; i < host->info->nb_pts; i++) | |
84 | INIT_WORK(&host->syncpt[i].intr.work, syncpt_thresh_work); | |
85 | ||
86 | err = devm_request_irq(host->dev, host->intr_syncpt_irq, | |
87 | syncpt_thresh_isr, IRQF_SHARED, | |
88 | "host1x_syncpt", host); | |
89 | if (IS_ERR_VALUE(err)) { | |
90 | WARN_ON(1); | |
91 | return err; | |
92 | } | |
93 | ||
94 | /* disable the ip_busy_timeout. this prevents write drops */ | |
95 | host1x_sync_writel(host, 0, HOST1X_SYNC_IP_BUSY_TIMEOUT); | |
96 | ||
97 | /* | |
98 | * increase the auto-ack timout to the maximum value. 2d will hang | |
99 | * otherwise on Tegra2. | |
100 | */ | |
101 | host1x_sync_writel(host, 0xff, HOST1X_SYNC_CTXSW_TIMEOUT_CFG); | |
102 | ||
103 | /* update host clocks per usec */ | |
104 | host1x_sync_writel(host, cpm, HOST1X_SYNC_USEC_CLK); | |
105 | ||
106 | return 0; | |
107 | } | |
108 | ||
109 | static void _host1x_intr_set_syncpt_threshold(struct host1x *host, | |
110 | u32 id, u32 thresh) | |
111 | { | |
112 | host1x_sync_writel(host, thresh, HOST1X_SYNC_SYNCPT_INT_THRESH(id)); | |
113 | } | |
114 | ||
115 | static void _host1x_intr_enable_syncpt_intr(struct host1x *host, u32 id) | |
116 | { | |
117 | host1x_sync_writel(host, BIT_MASK(id), | |
118 | HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(BIT_WORD(id))); | |
119 | } | |
120 | ||
121 | static void _host1x_intr_disable_syncpt_intr(struct host1x *host, u32 id) | |
122 | { | |
123 | host1x_sync_writel(host, BIT_MASK(id), | |
124 | HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(BIT_WORD(id))); | |
125 | host1x_sync_writel(host, BIT_MASK(id), | |
126 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(BIT_WORD(id))); | |
127 | } | |
128 | ||
129 | static int _host1x_free_syncpt_irq(struct host1x *host) | |
130 | { | |
131 | devm_free_irq(host->dev, host->intr_syncpt_irq, host); | |
132 | flush_workqueue(host->intr_wq); | |
133 | return 0; | |
134 | } | |
135 | ||
136 | static const struct host1x_intr_ops host1x_intr_ops = { | |
137 | .init_host_sync = _host1x_intr_init_host_sync, | |
138 | .set_syncpt_threshold = _host1x_intr_set_syncpt_threshold, | |
139 | .enable_syncpt_intr = _host1x_intr_enable_syncpt_intr, | |
140 | .disable_syncpt_intr = _host1x_intr_disable_syncpt_intr, | |
141 | .disable_all_syncpt_intrs = _host1x_intr_disable_all_syncpt_intrs, | |
142 | .free_syncpt_irq = _host1x_free_syncpt_irq, | |
143 | }; |