Rev 3746 | Rev 4126 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2351 | Serge | 1 | /* i915_irq.c -- IRQ support for the I915 -*- linux-c -*- |
2 | */ |
||
3 | /* |
||
4 | * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. |
||
5 | * All Rights Reserved. |
||
6 | * |
||
7 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
8 | * copy of this software and associated documentation files (the |
||
9 | * "Software"), to deal in the Software without restriction, including |
||
10 | * without limitation the rights to use, copy, modify, merge, publish, |
||
11 | * distribute, sub license, and/or sell copies of the Software, and to |
||
12 | * permit persons to whom the Software is furnished to do so, subject to |
||
13 | * the following conditions: |
||
14 | * |
||
15 | * The above copyright notice and this permission notice (including the |
||
16 | * next paragraph) shall be included in all copies or substantial portions |
||
17 | * of the Software. |
||
18 | * |
||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||
20 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||
21 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
||
22 | * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR |
||
23 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
||
24 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
||
25 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||
26 | * |
||
27 | */ |
||
28 | |||
3746 | Serge | 29 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
3031 | serge | 30 | |
31 | #include |
||
32 | #include |
||
33 | #include |
||
2351 | Serge | 34 | #include "i915_drv.h" |
35 | #include "i915_trace.h" |
||
36 | #include "intel_drv.h" |
||
37 | |||
4104 | Serge | 38 | #define assert_spin_locked(a) |
39 | |||
3746 | Serge | 40 | static const u32 hpd_ibx[] = { |
41 | [HPD_CRT] = SDE_CRT_HOTPLUG, |
||
42 | [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG, |
||
43 | [HPD_PORT_B] = SDE_PORTB_HOTPLUG, |
||
44 | [HPD_PORT_C] = SDE_PORTC_HOTPLUG, |
||
45 | [HPD_PORT_D] = SDE_PORTD_HOTPLUG |
||
46 | }; |
||
3031 | serge | 47 | |
3746 | Serge | 48 | static const u32 hpd_cpt[] = { |
49 | [HPD_CRT] = SDE_CRT_HOTPLUG_CPT, |
||
50 | [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG_CPT, |
||
51 | [HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT, |
||
52 | [HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT, |
||
53 | [HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT |
||
54 | }; |
||
55 | |||
56 | static const u32 hpd_mask_i915[] = { |
||
57 | [HPD_CRT] = CRT_HOTPLUG_INT_EN, |
||
58 | [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_EN, |
||
59 | [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_EN, |
||
60 | [HPD_PORT_B] = PORTB_HOTPLUG_INT_EN, |
||
61 | [HPD_PORT_C] = PORTC_HOTPLUG_INT_EN, |
||
62 | [HPD_PORT_D] = PORTD_HOTPLUG_INT_EN |
||
63 | }; |
||
64 | |||
65 | static const u32 hpd_status_gen4[] = { |
||
66 | [HPD_CRT] = CRT_HOTPLUG_INT_STATUS, |
||
67 | [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X, |
||
68 | [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X, |
||
69 | [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS, |
||
70 | [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS, |
||
71 | [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS |
||
72 | }; |
||
73 | |||
74 | static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */ |
||
75 | [HPD_CRT] = CRT_HOTPLUG_INT_STATUS, |
||
76 | [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915, |
||
77 | [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I915, |
||
78 | [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS, |
||
79 | [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS, |
||
80 | [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS |
||
81 | }; |
||
82 | |||
83 | |||
3031 | serge | 84 | #define pr_err(fmt, ...) \ |
85 | printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) |
||
86 | |||
87 | |||
2352 | Serge | 88 | #define DRM_WAKEUP( queue ) wake_up( queue ) |
89 | #define DRM_INIT_WAITQUEUE( queue ) init_waitqueue_head( queue ) |
||
90 | |||
2351 | Serge | 91 | #define MAX_NOPID ((u32)~0) |
92 | |||
93 | |||
94 | |||
95 | /* For display hotplug interrupt */ |
||
96 | static void |
||
97 | ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) |
||
98 | { |
||
4104 | Serge | 99 | assert_spin_locked(&dev_priv->irq_lock); |
100 | |||
101 | if (dev_priv->pc8.irqs_disabled) { |
||
102 | WARN(1, "IRQs disabled\n"); |
||
103 | dev_priv->pc8.regsave.deimr &= ~mask; |
||
104 | return; |
||
105 | } |
||
106 | |||
2351 | Serge | 107 | if ((dev_priv->irq_mask & mask) != 0) { |
108 | dev_priv->irq_mask &= ~mask; |
||
109 | I915_WRITE(DEIMR, dev_priv->irq_mask); |
||
110 | POSTING_READ(DEIMR); |
||
111 | } |
||
112 | } |
||
113 | |||
3746 | Serge | 114 | static void |
2351 | Serge | 115 | ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask) |
116 | { |
||
4104 | Serge | 117 | assert_spin_locked(&dev_priv->irq_lock); |
118 | |||
119 | if (dev_priv->pc8.irqs_disabled) { |
||
120 | WARN(1, "IRQs disabled\n"); |
||
121 | dev_priv->pc8.regsave.deimr |= mask; |
||
122 | return; |
||
123 | } |
||
124 | |||
2351 | Serge | 125 | if ((dev_priv->irq_mask & mask) != mask) { |
126 | dev_priv->irq_mask |= mask; |
||
127 | I915_WRITE(DEIMR, dev_priv->irq_mask); |
||
128 | POSTING_READ(DEIMR); |
||
129 | } |
||
130 | } |
||
3031 | serge | 131 | |
4104 | Serge | 132 | /** |
133 | * ilk_update_gt_irq - update GTIMR |
||
134 | * @dev_priv: driver private |
||
135 | * @interrupt_mask: mask of interrupt bits to update |
||
136 | * @enabled_irq_mask: mask of interrupt bits to enable |
||
137 | */ |
||
138 | static void ilk_update_gt_irq(struct drm_i915_private *dev_priv, |
||
139 | uint32_t interrupt_mask, |
||
140 | uint32_t enabled_irq_mask) |
||
141 | { |
||
142 | assert_spin_locked(&dev_priv->irq_lock); |
||
143 | |||
144 | if (dev_priv->pc8.irqs_disabled) { |
||
145 | WARN(1, "IRQs disabled\n"); |
||
146 | dev_priv->pc8.regsave.gtimr &= ~interrupt_mask; |
||
147 | dev_priv->pc8.regsave.gtimr |= (~enabled_irq_mask & |
||
148 | interrupt_mask); |
||
149 | return; |
||
150 | } |
||
151 | |||
152 | dev_priv->gt_irq_mask &= ~interrupt_mask; |
||
153 | dev_priv->gt_irq_mask |= (~enabled_irq_mask & interrupt_mask); |
||
154 | I915_WRITE(GTIMR, dev_priv->gt_irq_mask); |
||
155 | POSTING_READ(GTIMR); |
||
156 | } |
||
157 | |||
158 | void ilk_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask) |
||
159 | { |
||
160 | ilk_update_gt_irq(dev_priv, mask, mask); |
||
161 | } |
||
162 | |||
163 | void ilk_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask) |
||
164 | { |
||
165 | ilk_update_gt_irq(dev_priv, mask, 0); |
||
166 | } |
||
167 | |||
168 | /** |
||
169 | * snb_update_pm_irq - update GEN6_PMIMR |
||
170 | * @dev_priv: driver private |
||
171 | * @interrupt_mask: mask of interrupt bits to update |
||
172 | * @enabled_irq_mask: mask of interrupt bits to enable |
||
173 | */ |
||
174 | static void snb_update_pm_irq(struct drm_i915_private *dev_priv, |
||
175 | uint32_t interrupt_mask, |
||
176 | uint32_t enabled_irq_mask) |
||
177 | { |
||
178 | uint32_t new_val; |
||
179 | |||
180 | assert_spin_locked(&dev_priv->irq_lock); |
||
181 | |||
182 | if (dev_priv->pc8.irqs_disabled) { |
||
183 | WARN(1, "IRQs disabled\n"); |
||
184 | dev_priv->pc8.regsave.gen6_pmimr &= ~interrupt_mask; |
||
185 | dev_priv->pc8.regsave.gen6_pmimr |= (~enabled_irq_mask & |
||
186 | interrupt_mask); |
||
187 | return; |
||
188 | } |
||
189 | |||
190 | new_val = dev_priv->pm_irq_mask; |
||
191 | new_val &= ~interrupt_mask; |
||
192 | new_val |= (~enabled_irq_mask & interrupt_mask); |
||
193 | |||
194 | if (new_val != dev_priv->pm_irq_mask) { |
||
195 | dev_priv->pm_irq_mask = new_val; |
||
196 | I915_WRITE(GEN6_PMIMR, dev_priv->pm_irq_mask); |
||
197 | POSTING_READ(GEN6_PMIMR); |
||
198 | } |
||
199 | } |
||
200 | |||
201 | void snb_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask) |
||
202 | { |
||
203 | snb_update_pm_irq(dev_priv, mask, mask); |
||
204 | } |
||
205 | |||
206 | void snb_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask) |
||
207 | { |
||
208 | snb_update_pm_irq(dev_priv, mask, 0); |
||
209 | } |
||
210 | |||
211 | static bool ivb_can_enable_err_int(struct drm_device *dev) |
||
212 | { |
||
213 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
214 | struct intel_crtc *crtc; |
||
215 | enum pipe pipe; |
||
216 | |||
217 | assert_spin_locked(&dev_priv->irq_lock); |
||
218 | |||
219 | for_each_pipe(pipe) { |
||
220 | crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); |
||
221 | |||
222 | if (crtc->cpu_fifo_underrun_disabled) |
||
223 | return false; |
||
224 | } |
||
225 | |||
226 | return true; |
||
227 | } |
||
228 | |||
229 | static bool cpt_can_enable_serr_int(struct drm_device *dev) |
||
230 | { |
||
231 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
232 | enum pipe pipe; |
||
233 | struct intel_crtc *crtc; |
||
234 | |||
235 | assert_spin_locked(&dev_priv->irq_lock); |
||
236 | |||
237 | for_each_pipe(pipe) { |
||
238 | crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); |
||
239 | |||
240 | if (crtc->pch_fifo_underrun_disabled) |
||
241 | return false; |
||
242 | } |
||
243 | |||
244 | return true; |
||
245 | } |
||
246 | |||
247 | static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev, |
||
248 | enum pipe pipe, bool enable) |
||
249 | { |
||
250 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
251 | uint32_t bit = (pipe == PIPE_A) ? DE_PIPEA_FIFO_UNDERRUN : |
||
252 | DE_PIPEB_FIFO_UNDERRUN; |
||
253 | |||
254 | if (enable) |
||