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> | |
7ede0b0b | 23 | |
fc3be3e8 TR |
24 | #include "../intr.h" |
25 | #include "../dev.h" | |
7ede0b0b TB |
26 | |
27 | /* | |
28 | * Sync point threshold interrupt service function | |
29 | * Handles sync point threshold triggers, in interrupt context | |
30 | */ | |
31 | static void host1x_intr_syncpt_handle(struct host1x_syncpt *syncpt) | |
32 | { | |
33 | unsigned int id = syncpt->id; | |
34 | struct host1x *host = syncpt->host; | |
35 | ||
36 | host1x_sync_writel(host, BIT_MASK(id), | |
37 | HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(BIT_WORD(id))); | |
38 | host1x_sync_writel(host, BIT_MASK(id), | |
39 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(BIT_WORD(id))); | |
40 | ||
57574bd7 | 41 | schedule_work(&syncpt->intr.work); |
7ede0b0b TB |
42 | } |
43 | ||
44 | static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id) | |
45 | { | |
46 | struct host1x *host = dev_id; | |
47 | unsigned long reg; | |
14c95fc8 | 48 | unsigned int i, id; |
7ede0b0b | 49 | |
22bbd5d9 | 50 | for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); i++) { |
7ede0b0b TB |
51 | reg = host1x_sync_readl(host, |
52 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i)); | |
53 | for_each_set_bit(id, ®, BITS_PER_LONG) { | |
54 | struct host1x_syncpt *syncpt = | |
55 | host->syncpt + (i * BITS_PER_LONG + id); | |
56 | host1x_intr_syncpt_handle(syncpt); | |
57 | } | |
58 | } | |
59 | ||
60 | return IRQ_HANDLED; | |
61 | } | |
62 | ||
63 | static void _host1x_intr_disable_all_syncpt_intrs(struct host1x *host) | |
64 | { | |
14c95fc8 | 65 | unsigned int i; |
7ede0b0b | 66 | |
22bbd5d9 | 67 | for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); ++i) { |
7ede0b0b TB |
68 | host1x_sync_writel(host, 0xffffffffu, |
69 | HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(i)); | |
70 | host1x_sync_writel(host, 0xffffffffu, | |
71 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i)); | |
72 | } | |
73 | } | |
74 | ||
0b8070d1 TR |
75 | static int |
76 | _host1x_intr_init_host_sync(struct host1x *host, u32 cpm, | |
77 | void (*syncpt_thresh_work)(struct work_struct *)) | |
7ede0b0b | 78 | { |
14c95fc8 TR |
79 | unsigned int i; |
80 | int err; | |
7ede0b0b TB |
81 | |
82 | host1x_hw_intr_disable_all_syncpt_intrs(host); | |
83 | ||
84 | for (i = 0; i < host->info->nb_pts; i++) | |
85 | INIT_WORK(&host->syncpt[i].intr.work, syncpt_thresh_work); | |
86 | ||
87 | err = devm_request_irq(host->dev, host->intr_syncpt_irq, | |
88 | syncpt_thresh_isr, IRQF_SHARED, | |
89 | "host1x_syncpt", host); | |
287980e4 | 90 | if (err < 0) { |
7ede0b0b TB |
91 | WARN_ON(1); |
92 | return err; | |
93 | } | |
94 | ||
95 | /* disable the ip_busy_timeout. this prevents write drops */ | |
96 | host1x_sync_writel(host, 0, HOST1X_SYNC_IP_BUSY_TIMEOUT); | |
97 | ||
98 | /* | |
99 | * increase the auto-ack timout to the maximum value. 2d will hang | |
100 | * otherwise on Tegra2. | |
101 | */ | |
102 | host1x_sync_writel(host, 0xff, HOST1X_SYNC_CTXSW_TIMEOUT_CFG); | |
103 | ||
104 | /* update host clocks per usec */ | |
105 | host1x_sync_writel(host, cpm, HOST1X_SYNC_USEC_CLK); | |
106 | ||
107 | return 0; | |
108 | } | |
109 | ||
110 | static void _host1x_intr_set_syncpt_threshold(struct host1x *host, | |
5c0d8d38 TR |
111 | unsigned int id, |
112 | u32 thresh) | |
7ede0b0b TB |
113 | { |
114 | host1x_sync_writel(host, thresh, HOST1X_SYNC_SYNCPT_INT_THRESH(id)); | |
115 | } | |
116 | ||
5c0d8d38 TR |
117 | static void _host1x_intr_enable_syncpt_intr(struct host1x *host, |
118 | unsigned int id) | |
7ede0b0b TB |
119 | { |
120 | host1x_sync_writel(host, BIT_MASK(id), | |
121 | HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(BIT_WORD(id))); | |
122 | } | |
123 | ||
5c0d8d38 TR |
124 | static void _host1x_intr_disable_syncpt_intr(struct host1x *host, |
125 | unsigned int id) | |
7ede0b0b TB |
126 | { |
127 | host1x_sync_writel(host, BIT_MASK(id), | |
128 | HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(BIT_WORD(id))); | |
129 | host1x_sync_writel(host, BIT_MASK(id), | |
130 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(BIT_WORD(id))); | |
131 | } | |
132 | ||
133 | static int _host1x_free_syncpt_irq(struct host1x *host) | |
134 | { | |
14c95fc8 | 135 | unsigned int i; |
57574bd7 | 136 | |
7ede0b0b | 137 | devm_free_irq(host->dev, host->intr_syncpt_irq, host); |
57574bd7 BS |
138 | |
139 | for (i = 0; i < host->info->nb_pts; i++) | |
140 | cancel_work_sync(&host->syncpt[i].intr.work); | |
0b8070d1 | 141 | |
7ede0b0b TB |
142 | return 0; |
143 | } | |
144 | ||
145 | static const struct host1x_intr_ops host1x_intr_ops = { | |
146 | .init_host_sync = _host1x_intr_init_host_sync, | |
147 | .set_syncpt_threshold = _host1x_intr_set_syncpt_threshold, | |
148 | .enable_syncpt_intr = _host1x_intr_enable_syncpt_intr, | |
149 | .disable_syncpt_intr = _host1x_intr_disable_syncpt_intr, | |
150 | .disable_all_syncpt_intrs = _host1x_intr_disable_all_syncpt_intrs, | |
151 | .free_syncpt_irq = _host1x_free_syncpt_irq, | |
152 | }; |