Subversion Repositories Kolibri OS

Rev

Rev 4539 | Rev 5060 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1963 serge 1
/**
2
 * \file drm_irq.c
3
 * IRQ support
4
 *
5
 * \author Rickard E. (Rik) Faith 
6
 * \author Gareth Hughes 
7
 */
8
 
9
/*
10
 * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com
11
 *
12
 * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
13
 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
14
 * All Rights Reserved.
15
 *
16
 * Permission is hereby granted, free of charge, to any person obtaining a
17
 * copy of this software and associated documentation files (the "Software"),
18
 * to deal in the Software without restriction, including without limitation
19
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
20
 * and/or sell copies of the Software, and to permit persons to whom the
21
 * Software is furnished to do so, subject to the following conditions:
22
 *
23
 * The above copyright notice and this permission notice (including the next
24
 * paragraph) shall be included in all copies or substantial portions of the
25
 * Software.
26
 *
27
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
30
 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
31
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
32
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
33
 * OTHER DEALINGS IN THE SOFTWARE.
34
 */
35
 
3031 serge 36
#include 
1963 serge 37
#include 
38
//#include "drm_trace.h"
39
 
40
//#include    /* For task queue support */
41
#include 
42
 
43
//#include 
3031 serge 44
#include 
1963 serge 45
 
46
/* Access macro for slots in vblank timestamp ringbuffer. */
4560 Serge 47
#define vblanktimestamp(dev, crtc, count) \
48
	((dev)->vblank[crtc].time[(count) % DRM_VBLANKTIME_RBSIZE])
1963 serge 49
 
50
/* Retry timestamp calculation up to 3 times to satisfy
51
 * drm_timestamp_precision before giving up.
52
 */
53
#define DRM_TIMESTAMP_MAXRETRIES 3
54
 
55
/* Threshold in nanoseconds for detection of redundant
56
 * vblank irq in drm_handle_vblank(). 1 msec should be ok.
57
 */
58
#define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000
59
 
60
 
4075 Serge 61
irqreturn_t device_irq_handler(struct drm_device *dev)
62
{
63
 
4104 Serge 64
//    printf("video irq\n");
4075 Serge 65
 
66
//    printf("device %p driver %p handler %p\n", dev, dev->driver, dev->driver->irq_handler) ;
67
 
68
    return dev->driver->irq_handler(0, dev);
69
}
70
 
71
/**
72
 * Install IRQ handler.
73
 *
74
 * \param dev DRM device.
75
 *
76
 * Initializes the IRQ related data. Installs the handler, calling the driver
77
 * \c irq_preinstall() and \c irq_postinstall() functions
78
 * before and after the installation.
79
 */
80
int drm_irq_install(struct drm_device *dev)
81
{
82
	int ret;
83
    unsigned long sh_flags = 0;
84
	char *irqname;
85
 
4293 Serge 86
	if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
87
		return -EINVAL;
4075 Serge 88
 
89
	if (drm_dev_to_irq(dev) == 0)
90
		return -EINVAL;
91
 
92
    mutex_lock(&dev->struct_mutex);
93
 
94
    /* Driver must have been initialized */
95
    if (!dev->dev_private) {
96
            mutex_unlock(&dev->struct_mutex);
97
            return -EINVAL;
98
    }
99
 
100
    if (dev->irq_enabled) {
101
            mutex_unlock(&dev->struct_mutex);
102
            return -EBUSY;
103
    }
4560 Serge 104
	dev->irq_enabled = true;
4075 Serge 105
    mutex_unlock(&dev->struct_mutex);
106
 
107
    DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev));
108
 
109
    /* Before installing handler */
110
    if (dev->driver->irq_preinstall)
111
            dev->driver->irq_preinstall(dev);
112
 
113
    ret = !AttachIntHandler(drm_dev_to_irq(dev), device_irq_handler, (u32)dev);
114
 
115
    /* After installing handler */
116
    if (dev->driver->irq_postinstall)
117
            ret = dev->driver->irq_postinstall(dev);
118
 
119
    if (ret < 0) {
4104 Serge 120
		dev->irq_enabled = 0;
4539 Serge 121
        DRM_ERROR(__FUNCTION__);
4075 Serge 122
    }
123
 
124
    u16_t cmd = PciRead16(dev->pdev->busnr, dev->pdev->devfn, 4);
125
    cmd&= ~(1<<10);
126
    PciWrite16(dev->pdev->busnr, dev->pdev->devfn, 4, cmd);
127
 
128
    return ret;
129
}
130
EXPORT_SYMBOL(drm_irq_install);
131
 
132
 
1963 serge 133
 
134
 
135
u64 div64_u64(u64 dividend, u64 divisor)
136
{
137
        u32 high, d;
138
 
139
        high = divisor >> 32;
140
        if (high) {
141
                unsigned int shift = fls(high);
142
 
143
                d = divisor >> shift;
144
                dividend >>= shift;
145
        } else
146
                d = divisor;
147
 
148
        return div_u64(dividend, d);
149
}
150
 
151
/**
4560 Serge 152
 * drm_calc_timestamping_constants - Calculate vblank timestamp constants
1963 serge 153
 *
154
 * @crtc drm_crtc whose timestamp constants should be updated.
4560 Serge 155
 * @mode display mode containing the scanout timings
1963 serge 156
 *
4560 Serge 157
 * Calculate and store various constants which are later
158
 * needed by vblank and swap-completion timestamping, e.g,
159
 * by drm_calc_vbltimestamp_from_scanoutpos(). They are
160
 * derived from crtc's true scanout timing, so they take
161
 * things like panel scaling or other adjustments into account.
1963 serge 162
 */
4560 Serge 163
void drm_calc_timestamping_constants(struct drm_crtc *crtc,
164
				     const struct drm_display_mode *mode)
1963 serge 165
{
4560 Serge 166
	int linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0;
167
	int dotclock = mode->crtc_clock;
1963 serge 168
 
4560 Serge 169
	/* Valid dotclock? */
170
	if (dotclock > 0) {
171
		int frame_size = mode->crtc_htotal * mode->crtc_vtotal;
1963 serge 172
 
4560 Serge 173
		/*
174
		 * Convert scanline length in pixels and video
175
		 * dot clock to line duration, frame duration
176
		 * and pixel duration in nanoseconds:
1963 serge 177
	 */
4560 Serge 178
		pixeldur_ns = 1000000 / dotclock;
179
		linedur_ns  = div_u64((u64) mode->crtc_htotal * 1000000, dotclock);
180
		framedur_ns = div_u64((u64) frame_size * 1000000, dotclock);
1963 serge 181
 
4560 Serge 182
		/*
183
		 * Fields of interlaced scanout modes are only half a frame duration.
1963 serge 184
		 */
4560 Serge 185
		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
186
			framedur_ns /= 2;
1963 serge 187
	} else
188
		DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n",
189
			  crtc->base.id);
190
 
191
	crtc->pixeldur_ns = pixeldur_ns;
192
	crtc->linedur_ns  = linedur_ns;
193
	crtc->framedur_ns = framedur_ns;
194
 
195
	DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n",
4560 Serge 196
		  crtc->base.id, mode->crtc_htotal,
197
		  mode->crtc_vtotal, mode->crtc_vdisplay);
1963 serge 198
	DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n",
4560 Serge 199
		  crtc->base.id, dotclock, framedur_ns,
200
		  linedur_ns, pixeldur_ns);
1963 serge 201
}
4293 Serge 202
EXPORT_SYMBOL(drm_calc_timestamping_constants);
1963 serge 203
 
4293 Serge 204
/**
205
 * drm_calc_vbltimestamp_from_scanoutpos - helper routine for kms
206
 * drivers. Implements calculation of exact vblank timestamps from
207
 * given drm_display_mode timings and current video scanout position
208
 * of a crtc. This can be called from within get_vblank_timestamp()
209
 * implementation of a kms driver to implement the actual timestamping.
210
 *
211
 * Should return timestamps conforming to the OML_sync_control OpenML
212
 * extension specification. The timestamp corresponds to the end of
213
 * the vblank interval, aka start of scanout of topmost-leftmost display
214
 * pixel in the following video frame.
215
 *
216
 * Requires support for optional dev->driver->get_scanout_position()
217
 * in kms driver, plus a bit of setup code to provide a drm_display_mode
218
 * that corresponds to the true scanout timing.
219
 *
220
 * The current implementation only handles standard video modes. It
221
 * returns as no operation if a doublescan or interlaced video mode is
222
 * active. Higher level code is expected to handle this.
223
 *
224
 * @dev: DRM device.
225
 * @crtc: Which crtc's vblank timestamp to retrieve.
226
 * @max_error: Desired maximum allowable error in timestamps (nanosecs).
227
 *             On return contains true maximum error of timestamp.
228
 * @vblank_time: Pointer to struct timeval which should receive the timestamp.
229
 * @flags: Flags to pass to driver:
230
 *         0 = Default.
231
 *         DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler.
232
 * @refcrtc: drm_crtc* of crtc which defines scanout timing.
4560 Serge 233
 * @mode: mode which defines the scanout timings
4293 Serge 234
 *
235
 * Returns negative value on error, failure or if not supported in current
236
 * video mode:
237
 *
238
 * -EINVAL   - Invalid crtc.
239
 * -EAGAIN   - Temporary unavailable, e.g., called before initial modeset.
240
 * -ENOTSUPP - Function not supported in current display mode.
241
 * -EIO      - Failed, e.g., due to failed scanout position query.
242
 *
243
 * Returns or'ed positive status flags on success:
244
 *
245
 * DRM_VBLANKTIME_SCANOUTPOS_METHOD - Signal this method used for timestamping.
246
 * DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval.
247
 *
248
 */
249
int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
250
					  int *max_error,
251
					  struct timeval *vblank_time,
252
					  unsigned flags,
4560 Serge 253
					  const struct drm_crtc *refcrtc,
254
					  const struct drm_display_mode *mode)
4293 Serge 255
{
256
	struct timeval tv_etime;
4560 Serge 257
	int vbl_status;
4293 Serge 258
	int vpos, hpos, i;
4560 Serge 259
	int framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns;
4293 Serge 260
	bool invbl;
3031 serge 261
 
4293 Serge 262
	if (crtc < 0 || crtc >= dev->num_crtcs) {
263
		DRM_ERROR("Invalid crtc %d\n", crtc);
264
		return -EINVAL;
265
	}
266
 
267
	/* Scanout position query not supported? Should not happen. */
268
	if (!dev->driver->get_scanout_position) {
269
		DRM_ERROR("Called from driver w/o get_scanout_position()!?\n");
270
		return -EIO;
271
	}
272
 
273
	/* Durations of frames, lines, pixels in nanoseconds. */
274
	framedur_ns = refcrtc->framedur_ns;
275
	linedur_ns  = refcrtc->linedur_ns;
276
	pixeldur_ns = refcrtc->pixeldur_ns;
277
 
278
	/* If mode timing undefined, just return as no-op:
279
	 * Happens during initial modesetting of a crtc.
280
	 */
4560 Serge 281
	if (framedur_ns == 0) {
4293 Serge 282
		DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc);
283
		return -EAGAIN;
284
	}
285
 
286
	return -EIO;
287
}
288
EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos);
289
 
290
 
3031 serge 291
/**
292
 * drm_vblank_pre_modeset - account for vblanks across mode sets
293
 * @dev: DRM device
294
 * @crtc: CRTC in question
295
 *
296
 * Account for vblank events across mode setting events, which will likely
297
 * reset the hardware frame counter.
298
 */
299
void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
300
{
301
#if 0
302
    /* vblank is not initialized (IRQ not installed ?) */
303
    if (!dev->num_crtcs)
304
        return;
305
    /*
306
     * To avoid all the problems that might happen if interrupts
307
     * were enabled/disabled around or between these calls, we just
308
     * have the kernel take a reference on the CRTC (just once though
309
     * to avoid corrupting the count if multiple, mismatch calls occur),
310
     * so that interrupts remain enabled in the interim.
311
     */
4560 Serge 312
	if (!dev->vblank[crtc].inmodeset) {
313
		dev->vblank[crtc].inmodeset = 0x1;
3031 serge 314
        if (drm_vblank_get(dev, crtc) == 0)
4560 Serge 315
			dev->vblank[crtc].inmodeset |= 0x2;
3031 serge 316
    }
317
#endif
318
}
319
EXPORT_SYMBOL(drm_vblank_pre_modeset);
320
 
321
void drm_vblank_post_modeset(struct drm_device *dev, int crtc)
322
{
323
#if 0
324
    unsigned long irqflags;
325
 
4075 Serge 326
	/* vblank is not initialized (IRQ not installed ?), or has been freed */
327
	if (!dev->num_crtcs)
328
		return;
329
 
4560 Serge 330
	if (dev->vblank[crtc].inmodeset) {
3031 serge 331
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
4560 Serge 332
		dev->vblank_disable_allowed = true;
3031 serge 333
        spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
334
 
4560 Serge 335
		if (dev->vblank[crtc].inmodeset & 0x2)
3031 serge 336
            drm_vblank_put(dev, crtc);
337
 
4560 Serge 338
		dev->vblank[crtc].inmodeset = 0;
3031 serge 339
    }
340
#endif
341
}
342
EXPORT_SYMBOL(drm_vblank_post_modeset);