Subversion Repositories Kolibri OS

Rev

Rev 4293 | Rev 4560 | 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. */
47
#define vblanktimestamp(dev, crtc, count) ( \
48
	(dev)->_vblank_time[(crtc) * DRM_VBLANKTIME_RBSIZE + \
49
	((count) % DRM_VBLANKTIME_RBSIZE)])
50
 
51
/* Retry timestamp calculation up to 3 times to satisfy
52
 * drm_timestamp_precision before giving up.
53
 */
54
#define DRM_TIMESTAMP_MAXRETRIES 3
55
 
56
/* Threshold in nanoseconds for detection of redundant
57
 * vblank irq in drm_handle_vblank(). 1 msec should be ok.
58
 */
59
#define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000
60
 
61
 
4075 Serge 62
irqreturn_t device_irq_handler(struct drm_device *dev)
63
{
64
 
4104 Serge 65
//    printf("video irq\n");
4075 Serge 66
 
67
//    printf("device %p driver %p handler %p\n", dev, dev->driver, dev->driver->irq_handler) ;
68
 
69
    return dev->driver->irq_handler(0, dev);
70
}
71
 
72
/**
73
 * Install IRQ handler.
74
 *
75
 * \param dev DRM device.
76
 *
77
 * Initializes the IRQ related data. Installs the handler, calling the driver
78
 * \c irq_preinstall() and \c irq_postinstall() functions
79
 * before and after the installation.
80
 */
81
int drm_irq_install(struct drm_device *dev)
82
{
83
	int ret;
84
    unsigned long sh_flags = 0;
85
	char *irqname;
86
 
4293 Serge 87
	if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
88
		return -EINVAL;
4075 Serge 89
 
90
	if (drm_dev_to_irq(dev) == 0)
91
		return -EINVAL;
92
 
93
    mutex_lock(&dev->struct_mutex);
94
 
95
    /* Driver must have been initialized */
96
    if (!dev->dev_private) {
97
            mutex_unlock(&dev->struct_mutex);
98
            return -EINVAL;
99
    }
100
 
101
    if (dev->irq_enabled) {
102
            mutex_unlock(&dev->struct_mutex);
103
            return -EBUSY;
104
    }
105
    dev->irq_enabled = 1;
106
    mutex_unlock(&dev->struct_mutex);
107
 
108
    DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev));
109
 
110
    /* Before installing handler */
111
    if (dev->driver->irq_preinstall)
112
            dev->driver->irq_preinstall(dev);
113
 
114
    ret = !AttachIntHandler(drm_dev_to_irq(dev), device_irq_handler, (u32)dev);
115
 
116
    /* After installing handler */
117
    if (dev->driver->irq_postinstall)
118
            ret = dev->driver->irq_postinstall(dev);
119
 
120
    if (ret < 0) {
4104 Serge 121
		dev->irq_enabled = 0;
4539 Serge 122
        DRM_ERROR(__FUNCTION__);
4075 Serge 123
    }
124
 
125
    u16_t cmd = PciRead16(dev->pdev->busnr, dev->pdev->devfn, 4);
126
    cmd&= ~(1<<10);
127
    PciWrite16(dev->pdev->busnr, dev->pdev->devfn, 4, cmd);
128
 
129
    return ret;
130
}
131
EXPORT_SYMBOL(drm_irq_install);
132
 
133
 
1963 serge 134
 
135
 
136
u64 div64_u64(u64 dividend, u64 divisor)
137
{
138
        u32 high, d;
139
 
140
        high = divisor >> 32;
141
        if (high) {
142
                unsigned int shift = fls(high);
143
 
144
                d = divisor >> shift;
145
                dividend >>= shift;
146
        } else
147
                d = divisor;
148
 
149
        return div_u64(dividend, d);
150
}
151
 
152
/**
153
 * drm_calc_timestamping_constants - Calculate and
154
 * store various constants which are later needed by
155
 * vblank and swap-completion timestamping, e.g, by
156
 * drm_calc_vbltimestamp_from_scanoutpos().
157
 * They are derived from crtc's true scanout timing,
158
 * so they take things like panel scaling or other
159
 * adjustments into account.
160
 *
161
 * @crtc drm_crtc whose timestamp constants should be updated.
162
 *
163
 */
164
void drm_calc_timestamping_constants(struct drm_crtc *crtc)
165
{
166
	s64 linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0;
167
	u64 dotclock;
168
 
169
	/* Dot clock in Hz: */
170
	dotclock = (u64) crtc->hwmode.clock * 1000;
171
 
172
	/* Fields of interlaced scanout modes are only halve a frame duration.
173
	 * Double the dotclock to get halve the frame-/line-/pixelduration.
174
	 */
175
	if (crtc->hwmode.flags & DRM_MODE_FLAG_INTERLACE)
176
		dotclock *= 2;
177
 
178
	/* Valid dotclock? */
179
	if (dotclock > 0) {
3480 Serge 180
		int frame_size;
1963 serge 181
		/* Convert scanline length in pixels and video dot clock to
182
		 * line duration, frame duration and pixel duration in
183
		 * nanoseconds:
184
		 */
185
		pixeldur_ns = (s64) div64_u64(1000000000, dotclock);
186
		linedur_ns  = (s64) div64_u64(((u64) crtc->hwmode.crtc_htotal *
187
					      1000000000), dotclock);
3480 Serge 188
		frame_size = crtc->hwmode.crtc_htotal *
189
				crtc->hwmode.crtc_vtotal;
190
		framedur_ns = (s64) div64_u64((u64) frame_size * 1000000000,
191
					      dotclock);
1963 serge 192
	} else
193
		DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n",
194
			  crtc->base.id);
195
 
196
	crtc->pixeldur_ns = pixeldur_ns;
197
	crtc->linedur_ns  = linedur_ns;
198
	crtc->framedur_ns = framedur_ns;
199
 
200
	DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n",
201
		  crtc->base.id, crtc->hwmode.crtc_htotal,
202
		  crtc->hwmode.crtc_vtotal, crtc->hwmode.crtc_vdisplay);
203
	DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n",
204
		  crtc->base.id, (int) dotclock/1000, (int) framedur_ns,
205
		  (int) linedur_ns, (int) pixeldur_ns);
206
}
4293 Serge 207
EXPORT_SYMBOL(drm_calc_timestamping_constants);
1963 serge 208
 
4293 Serge 209
/**
210
 * drm_calc_vbltimestamp_from_scanoutpos - helper routine for kms
211
 * drivers. Implements calculation of exact vblank timestamps from
212
 * given drm_display_mode timings and current video scanout position
213
 * of a crtc. This can be called from within get_vblank_timestamp()
214
 * implementation of a kms driver to implement the actual timestamping.
215
 *
216
 * Should return timestamps conforming to the OML_sync_control OpenML
217
 * extension specification. The timestamp corresponds to the end of
218
 * the vblank interval, aka start of scanout of topmost-leftmost display
219
 * pixel in the following video frame.
220
 *
221
 * Requires support for optional dev->driver->get_scanout_position()
222
 * in kms driver, plus a bit of setup code to provide a drm_display_mode
223
 * that corresponds to the true scanout timing.
224
 *
225
 * The current implementation only handles standard video modes. It
226
 * returns as no operation if a doublescan or interlaced video mode is
227
 * active. Higher level code is expected to handle this.
228
 *
229
 * @dev: DRM device.
230
 * @crtc: Which crtc's vblank timestamp to retrieve.
231
 * @max_error: Desired maximum allowable error in timestamps (nanosecs).
232
 *             On return contains true maximum error of timestamp.
233
 * @vblank_time: Pointer to struct timeval which should receive the timestamp.
234
 * @flags: Flags to pass to driver:
235
 *         0 = Default.
236
 *         DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler.
237
 * @refcrtc: drm_crtc* of crtc which defines scanout timing.
238
 *
239
 * Returns negative value on error, failure or if not supported in current
240
 * video mode:
241
 *
242
 * -EINVAL   - Invalid crtc.
243
 * -EAGAIN   - Temporary unavailable, e.g., called before initial modeset.
244
 * -ENOTSUPP - Function not supported in current display mode.
245
 * -EIO      - Failed, e.g., due to failed scanout position query.
246
 *
247
 * Returns or'ed positive status flags on success:
248
 *
249
 * DRM_VBLANKTIME_SCANOUTPOS_METHOD - Signal this method used for timestamping.
250
 * DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval.
251
 *
252
 */
253
int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
254
					  int *max_error,
255
					  struct timeval *vblank_time,
256
					  unsigned flags,
257
					  struct drm_crtc *refcrtc)
258
{
259
//	ktime_t stime, etime, mono_time_offset;
260
	struct timeval tv_etime;
261
	struct drm_display_mode *mode;
262
	int vbl_status, vtotal, vdisplay;
263
	int vpos, hpos, i;
264
	s64 framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns;
265
	bool invbl;
3031 serge 266
 
4293 Serge 267
	if (crtc < 0 || crtc >= dev->num_crtcs) {
268
		DRM_ERROR("Invalid crtc %d\n", crtc);
269
		return -EINVAL;
270
	}
271
 
272
	/* Scanout position query not supported? Should not happen. */
273
	if (!dev->driver->get_scanout_position) {
274
		DRM_ERROR("Called from driver w/o get_scanout_position()!?\n");
275
		return -EIO;
276
	}
277
 
278
	mode = &refcrtc->hwmode;
279
	vtotal = mode->crtc_vtotal;
280
	vdisplay = mode->crtc_vdisplay;
281
 
282
	/* Durations of frames, lines, pixels in nanoseconds. */
283
	framedur_ns = refcrtc->framedur_ns;
284
	linedur_ns  = refcrtc->linedur_ns;
285
	pixeldur_ns = refcrtc->pixeldur_ns;
286
 
287
	/* If mode timing undefined, just return as no-op:
288
	 * Happens during initial modesetting of a crtc.
289
	 */
290
	if (vtotal <= 0 || vdisplay <= 0 || framedur_ns == 0) {
291
		DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc);
292
		return -EAGAIN;
293
	}
294
 
295
	return -EIO;
296
}
297
EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos);
298
 
299
 
3031 serge 300
/**
301
 * drm_vblank_pre_modeset - account for vblanks across mode sets
302
 * @dev: DRM device
303
 * @crtc: CRTC in question
304
 *
305
 * Account for vblank events across mode setting events, which will likely
306
 * reset the hardware frame counter.
307
 */
308
void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
309
{
310
#if 0
311
    /* vblank is not initialized (IRQ not installed ?) */
312
    if (!dev->num_crtcs)
313
        return;
314
    /*
315
     * To avoid all the problems that might happen if interrupts
316
     * were enabled/disabled around or between these calls, we just
317
     * have the kernel take a reference on the CRTC (just once though
318
     * to avoid corrupting the count if multiple, mismatch calls occur),
319
     * so that interrupts remain enabled in the interim.
320
     */
321
    if (!dev->vblank_inmodeset[crtc]) {
322
        dev->vblank_inmodeset[crtc] = 0x1;
323
        if (drm_vblank_get(dev, crtc) == 0)
324
            dev->vblank_inmodeset[crtc] |= 0x2;
325
    }
326
#endif
327
}
328
EXPORT_SYMBOL(drm_vblank_pre_modeset);
329
 
330
void drm_vblank_post_modeset(struct drm_device *dev, int crtc)
331
{
332
#if 0
333
    unsigned long irqflags;
334
 
4075 Serge 335
	/* vblank is not initialized (IRQ not installed ?), or has been freed */
336
	if (!dev->num_crtcs)
337
		return;
338
 
3031 serge 339
    if (dev->vblank_inmodeset[crtc]) {
340
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
341
        dev->vblank_disable_allowed = 1;
342
        spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
343
 
344
        if (dev->vblank_inmodeset[crtc] & 0x2)
345
            drm_vblank_put(dev, crtc);
346
 
347
        dev->vblank_inmodeset[crtc] = 0;
348
    }
349
#endif
350
}
351
EXPORT_SYMBOL(drm_vblank_post_modeset);