Subversion Repositories Kolibri OS

Rev

Rev 2352 | Go to most recent revision | Details | 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
 
29
#include 
30
//#include 
31
#include "drmP.h"
32
#include "drm.h"
33
#include "i915_drm.h"
34
#include "i915_drv.h"
35
#include "i915_trace.h"
36
#include "intel_drv.h"
37
 
38
#define MAX_NOPID ((u32)~0)
39
 
40
/**
41
 * Interrupts that are always left unmasked.
42
 *
43
 * Since pipe events are edge-triggered from the PIPESTAT register to IIR,
44
 * we leave them always unmasked in IMR and then control enabling them through
45
 * PIPESTAT alone.
46
 */
47
#define I915_INTERRUPT_ENABLE_FIX			\
48
	(I915_ASLE_INTERRUPT |				\
49
	 I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |		\
50
	 I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |		\
51
	 I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |	\
52
	 I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT |	\
53
	 I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
54
 
55
/** Interrupts that we mask and unmask at runtime. */
56
#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT | I915_BSD_USER_INTERRUPT)
57
 
58
#define I915_PIPE_VBLANK_STATUS	(PIPE_START_VBLANK_INTERRUPT_STATUS |\
59
				 PIPE_VBLANK_INTERRUPT_STATUS)
60
 
61
#define I915_PIPE_VBLANK_ENABLE	(PIPE_START_VBLANK_INTERRUPT_ENABLE |\
62
				 PIPE_VBLANK_INTERRUPT_ENABLE)
63
 
64
#define DRM_I915_VBLANK_PIPE_ALL	(DRM_I915_VBLANK_PIPE_A | \
65
					 DRM_I915_VBLANK_PIPE_B)
66
 
67
/* For display hotplug interrupt */
68
static void
69
ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
70
{
71
    if ((dev_priv->irq_mask & mask) != 0) {
72
        dev_priv->irq_mask &= ~mask;
73
        I915_WRITE(DEIMR, dev_priv->irq_mask);
74
        POSTING_READ(DEIMR);
75
    }
76
}
77
 
78
static inline void
79
ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
80
{
81
    if ((dev_priv->irq_mask & mask) != mask) {
82
        dev_priv->irq_mask |= mask;
83
        I915_WRITE(DEIMR, dev_priv->irq_mask);
84
        POSTING_READ(DEIMR);
85
    }
86
}
87
 
88
 
89
 
90
static int ironlake_irq_handler(struct drm_device *dev)
91
{
92
    drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
93
    int ret = IRQ_NONE;
94
    u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir;
95
    u32 hotplug_mask;
96
    struct drm_i915_master_private *master_priv;
97
    u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT;
98
 
99
    atomic_inc(&dev_priv->irq_received);
100
 
101
    if (IS_GEN6(dev))
102
        bsd_usr_interrupt = GT_GEN6_BSD_USER_INTERRUPT;
103
 
104
    /* disable master interrupt before clearing iir  */
105
    de_ier = I915_READ(DEIER);
106
    I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
107
    POSTING_READ(DEIER);
108
 
109
    de_iir = I915_READ(DEIIR);
110
    gt_iir = I915_READ(GTIIR);
111
    pch_iir = I915_READ(SDEIIR);
112
    pm_iir = I915_READ(GEN6_PMIIR);
113
 
114
    if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 &&
115
        (!IS_GEN6(dev) || pm_iir == 0))
116
        goto done;
117
 
118
    if (HAS_PCH_CPT(dev))
119
        hotplug_mask = SDE_HOTPLUG_MASK_CPT;
120
    else
121
        hotplug_mask = SDE_HOTPLUG_MASK;
122
 
123
    ret = IRQ_HANDLED;
124
 
125
 
126
//    if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY))
127
//        notify_ring(dev, &dev_priv->ring[RCS]);
128
//    if (gt_iir & bsd_usr_interrupt)
129
//        notify_ring(dev, &dev_priv->ring[VCS]);
130
//    if (gt_iir & GT_BLT_USER_INTERRUPT)
131
//        notify_ring(dev, &dev_priv->ring[BCS]);
132
 
133
//    if (de_iir & DE_GSE)
134
//        intel_opregion_gse_intr(dev);
135
 
136
//    if (de_iir & DE_PLANEA_FLIP_DONE) {
137
//        intel_prepare_page_flip(dev, 0);
138
//        intel_finish_page_flip_plane(dev, 0);
139
//    }
140
 
141
//    if (de_iir & DE_PLANEB_FLIP_DONE) {
142
//        intel_prepare_page_flip(dev, 1);
143
//        intel_finish_page_flip_plane(dev, 1);
144
//    }
145
 
146
//    if (de_iir & DE_PIPEA_VBLANK)
147
//        drm_handle_vblank(dev, 0);
148
 
149
//    if (de_iir & DE_PIPEB_VBLANK)
150
//        drm_handle_vblank(dev, 1);
151
 
152
    /* check event from PCH */
153
//    if (de_iir & DE_PCH_EVENT) {
154
//        if (pch_iir & hotplug_mask)
155
//            queue_work(dev_priv->wq, &dev_priv->hotplug_work);
156
//        pch_irq_handler(dev);
157
//    }
158
 
159
//    if (de_iir & DE_PCU_EVENT) {
160
//        I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS));
161
//        i915_handle_rps_change(dev);
162
//    }
163
 
164
    if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS) {
165
        /*
166
         * IIR bits should never already be set because IMR should
167
         * prevent an interrupt from being shown in IIR. The warning
168
         * displays a case where we've unsafely cleared
169
         * dev_priv->pm_iir. Although missing an interrupt of the same
170
         * type is not a problem, it displays a problem in the logic.
171
         *
172
         * The mask bit in IMR is cleared by rps_work.
173
         */
174
        unsigned long flags;
175
        spin_lock_irqsave(&dev_priv->rps_lock, flags);
176
        WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
177
        dev_priv->pm_iir |= pm_iir;
178
        I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir);
179
        POSTING_READ(GEN6_PMIMR);
180
        spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
181
//        queue_work(dev_priv->wq, &dev_priv->rps_work);
182
    }
183
 
184
    /* should clear PCH hotplug event before clear CPU irq */
185
    I915_WRITE(SDEIIR, pch_iir);
186
    I915_WRITE(GTIIR, gt_iir);
187
    I915_WRITE(DEIIR, de_iir);
188
    I915_WRITE(GEN6_PMIIR, pm_iir);
189
 
190
done:
191
    I915_WRITE(DEIER, de_ier);
192
    POSTING_READ(DEIER);
193
 
194
    return ret;
195
}
196
 
197
 
198
 
199
 
200
 
201
 
202
 
203
 
204
 
205
/* drm_dma.h hooks
206
*/
207
static void ironlake_irq_preinstall(struct drm_device *dev)
208
{
209
    drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
210
 
211
    atomic_set(&dev_priv->irq_received, 0);
212
 
213
//    INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
214
//    INIT_WORK(&dev_priv->error_work, i915_error_work_func);
215
//    if (IS_GEN6(dev) || IS_IVYBRIDGE(dev))
216
//        INIT_WORK(&dev_priv->rps_work, gen6_pm_rps_work);
217
 
218
    I915_WRITE(HWSTAM, 0xeffe);
219
 
220
    if (IS_GEN6(dev)) {
221
        /* Workaround stalls observed on Sandy Bridge GPUs by
222
         * making the blitter command streamer generate a
223
         * write to the Hardware Status Page for
224
         * MI_USER_INTERRUPT.  This appears to serialize the
225
         * previous seqno write out before the interrupt
226
         * happens.
227
         */
228
        I915_WRITE(GEN6_BLITTER_HWSTAM, ~GEN6_BLITTER_USER_INTERRUPT);
229
        I915_WRITE(GEN6_BSD_HWSTAM, ~GEN6_BSD_USER_INTERRUPT);
230
    }
231
 
232
    /* XXX hotplug from PCH */
233
 
234
    I915_WRITE(DEIMR, 0xffffffff);
235
    I915_WRITE(DEIER, 0x0);
236
    POSTING_READ(DEIER);
237
 
238
    /* and GT */
239
    I915_WRITE(GTIMR, 0xffffffff);
240
    I915_WRITE(GTIER, 0x0);
241
    POSTING_READ(GTIER);
242
 
243
    /* south display irq */
244
    I915_WRITE(SDEIMR, 0xffffffff);
245
    I915_WRITE(SDEIER, 0x0);
246
    POSTING_READ(SDEIER);
247
}
248
 
249
/*
250
 * Enable digital hotplug on the PCH, and configure the DP short pulse
251
 * duration to 2ms (which is the minimum in the Display Port spec)
252
 *
253
 * This register is the same on all known PCH chips.
254
 */
255
 
256
static void ironlake_enable_pch_hotplug(struct drm_device *dev)
257
{
258
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
259
	u32	hotplug;
260
 
261
	hotplug = I915_READ(PCH_PORT_HOTPLUG);
262
	hotplug &= ~(PORTD_PULSE_DURATION_MASK|PORTC_PULSE_DURATION_MASK|PORTB_PULSE_DURATION_MASK);
263
	hotplug |= PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_2ms;
264
	hotplug |= PORTC_HOTPLUG_ENABLE | PORTC_PULSE_DURATION_2ms;
265
	hotplug |= PORTB_HOTPLUG_ENABLE | PORTB_PULSE_DURATION_2ms;
266
	I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
267
}
268
 
269
static int ironlake_irq_postinstall(struct drm_device *dev)
270
{
271
    drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
272
    /* enable kind of interrupts always enabled */
273
    u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
274
               DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE;
275
    u32 render_irqs;
276
    u32 hotplug_mask;
277
 
278
//    DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue);
279
//    if (HAS_BSD(dev))
280
//        DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue);
281
//    if (HAS_BLT(dev))
282
//        DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue);
283
 
284
    dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
285
    dev_priv->irq_mask = ~display_mask;
286
 
287
    /* should always can generate irq */
288
    I915_WRITE(DEIIR, I915_READ(DEIIR));
289
    I915_WRITE(DEIMR, dev_priv->irq_mask);
290
    I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK);
291
    POSTING_READ(DEIER);
292
 
293
	dev_priv->gt_irq_mask = ~0;
294
 
295
    I915_WRITE(GTIIR, I915_READ(GTIIR));
296
    I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
297
 
298
    if (IS_GEN6(dev))
299
        render_irqs =
300
            GT_USER_INTERRUPT |
301
            GT_GEN6_BSD_USER_INTERRUPT |
302
            GT_BLT_USER_INTERRUPT;
303
    else
304
        render_irqs =
305
            GT_USER_INTERRUPT |
306
            GT_PIPE_NOTIFY |
307
            GT_BSD_USER_INTERRUPT;
308
    I915_WRITE(GTIER, render_irqs);
309
    POSTING_READ(GTIER);
310
 
311
    if (HAS_PCH_CPT(dev)) {
312
        hotplug_mask = (SDE_CRT_HOTPLUG_CPT |
313
                SDE_PORTB_HOTPLUG_CPT |
314
                SDE_PORTC_HOTPLUG_CPT |
315
                SDE_PORTD_HOTPLUG_CPT);
316
    } else {
317
        hotplug_mask = (SDE_CRT_HOTPLUG |
318
                SDE_PORTB_HOTPLUG |
319
                SDE_PORTC_HOTPLUG |
320
                SDE_PORTD_HOTPLUG |
321
                SDE_AUX_MASK);
322
    }
323
 
324
    dev_priv->pch_irq_mask = ~hotplug_mask;
325
 
326
    I915_WRITE(SDEIIR, I915_READ(SDEIIR));
327
    I915_WRITE(SDEIMR, dev_priv->pch_irq_mask);
328
    I915_WRITE(SDEIER, hotplug_mask);
329
    POSTING_READ(SDEIER);
330
 
331
    ironlake_enable_pch_hotplug(dev);
332
 
333
    if (IS_IRONLAKE_M(dev)) {
334
        /* Clear & enable PCU event interrupts */
335
        I915_WRITE(DEIIR, DE_PCU_EVENT);
336
        I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT);
337
        ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT);
338
    }
339
 
340
    return 0;
341
}
342
 
343
 
344
void intel_irq_init(struct drm_device *dev)
345
{
346
#if 0
347
	if (IS_IVYBRIDGE(dev)) {
348
		/* Share pre & uninstall handlers with ILK/SNB */
349
		dev->driver->irq_handler = ivybridge_irq_handler;
350
		dev->driver->irq_preinstall = ironlake_irq_preinstall;
351
		dev->driver->irq_postinstall = ivybridge_irq_postinstall;
352
		dev->driver->irq_uninstall = ironlake_irq_uninstall;
353
		dev->driver->enable_vblank = ivybridge_enable_vblank;
354
		dev->driver->disable_vblank = ivybridge_disable_vblank;
355
	} else if (HAS_PCH_SPLIT(dev)) {
356
		dev->driver->irq_handler = ironlake_irq_handler;
357
		dev->driver->irq_preinstall = ironlake_irq_preinstall;
358
		dev->driver->irq_postinstall = ironlake_irq_postinstall;
359
		dev->driver->irq_uninstall = ironlake_irq_uninstall;
360
		dev->driver->enable_vblank = ironlake_enable_vblank;
361
		dev->driver->disable_vblank = ironlake_disable_vblank;
362
	} else {
363
		dev->driver->irq_preinstall = i915_driver_irq_preinstall;
364
		dev->driver->irq_postinstall = i915_driver_irq_postinstall;
365
		dev->driver->irq_uninstall = i915_driver_irq_uninstall;
366
		dev->driver->irq_handler = i915_driver_irq_handler;
367
		dev->driver->enable_vblank = i915_enable_vblank;
368
		dev->driver->disable_vblank = i915_disable_vblank;
369
	}
370
#endif
371
}
372
 
373
 
374
static struct drm_device *irq_device;
375
 
376
void irq_handler_kms()
377
{
378
//    printf("%s\n",__FUNCTION__);
379
    ironlake_irq_handler(irq_device);
380
}
381
 
382
int drm_irq_install(struct drm_device *dev)
383
{
384
    int irq_line;
385
    int ret = 0;
386
 
387
    ENTER();
388
 
389
    mutex_lock(&dev->struct_mutex);
390
 
391
    /* Driver must have been initialized */
392
    if (!dev->dev_private) {
393
        mutex_unlock(&dev->struct_mutex);
394
        return -EINVAL;
395
    }
396
 
397
    if (dev->irq_enabled) {
398
        mutex_unlock(&dev->struct_mutex);
399
        return -EBUSY;
400
    }
401
    dev->irq_enabled = 1;
402
    mutex_unlock(&dev->struct_mutex);
403
 
404
    irq_device = dev;
405
    irq_line   = drm_dev_to_irq(dev);
406
 
407
    DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev));
408
 
409
    ironlake_irq_preinstall(dev);
410
 
411
    ret = AttachIntHandler(irq_line, irq_handler_kms, 2);
412
    if (ret == 0) {
413
        mutex_lock(&dev->struct_mutex);
414
        dev->irq_enabled = 0;
415
        mutex_unlock(&dev->struct_mutex);
416
        return ret;
417
    }
418
 
419
    ret = ironlake_irq_postinstall(dev);
420
 
421
//    if (ret < 0) {
422
//        mutex_lock(&dev->struct_mutex);
423
//        dev->irq_enabled = 0;
424
//        mutex_unlock(&dev->struct_mutex);
425
//        free_irq(drm_dev_to_irq(dev), dev);
426
//    }
427
 
428
    u16_t cmd = PciRead16(dev->pdev->busnr, dev->pdev->devfn, 4);
429
 
430
    cmd&= ~(1<<10);
431
 
432
    PciWrite16(dev->pdev->busnr, dev->pdev->devfn, 4, cmd);
433
 
434
    dbgprintf("PCI_CMD: %04x\n", cmd);
435
 
436
    DRM_INFO("i915: irq initialized.\n");
437
    LEAVE();
438
    return ret;
439
}
440
 
441
 
442