diff options
Diffstat (limited to 'drivers/gpu/drm/via/via_irq.c')
-rw-r--r-- | drivers/gpu/drm/via/via_irq.c | 105 |
1 files changed, 59 insertions, 46 deletions
diff --git a/drivers/gpu/drm/via/via_irq.c b/drivers/gpu/drm/via/via_irq.c index c6bb978a1106..665d319b927b 100644 --- a/drivers/gpu/drm/via/via_irq.c +++ b/drivers/gpu/drm/via/via_irq.c | |||
@@ -43,7 +43,7 @@ | |||
43 | #define VIA_REG_INTERRUPT 0x200 | 43 | #define VIA_REG_INTERRUPT 0x200 |
44 | 44 | ||
45 | /* VIA_REG_INTERRUPT */ | 45 | /* VIA_REG_INTERRUPT */ |
46 | #define VIA_IRQ_GLOBAL (1 << 31) | 46 | #define VIA_IRQ_GLOBAL (1 << 31) |
47 | #define VIA_IRQ_VBLANK_ENABLE (1 << 19) | 47 | #define VIA_IRQ_VBLANK_ENABLE (1 << 19) |
48 | #define VIA_IRQ_VBLANK_PENDING (1 << 3) | 48 | #define VIA_IRQ_VBLANK_PENDING (1 << 3) |
49 | #define VIA_IRQ_HQV0_ENABLE (1 << 11) | 49 | #define VIA_IRQ_HQV0_ENABLE (1 << 11) |
@@ -68,16 +68,15 @@ | |||
68 | 68 | ||
69 | static maskarray_t via_pro_group_a_irqs[] = { | 69 | static maskarray_t via_pro_group_a_irqs[] = { |
70 | {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010, | 70 | {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010, |
71 | 0x00000000}, | 71 | 0x00000000 }, |
72 | {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010, | 72 | {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010, |
73 | 0x00000000}, | 73 | 0x00000000 }, |
74 | {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0, | 74 | {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0, |
75 | VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, | 75 | VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, |
76 | {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1, | 76 | {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1, |
77 | VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, | 77 | VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, |
78 | }; | 78 | }; |
79 | static int via_num_pro_group_a = | 79 | static int via_num_pro_group_a = ARRAY_SIZE(via_pro_group_a_irqs); |
80 | sizeof(via_pro_group_a_irqs) / sizeof(maskarray_t); | ||
81 | static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3}; | 80 | static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3}; |
82 | 81 | ||
83 | static maskarray_t via_unichrome_irqs[] = { | 82 | static maskarray_t via_unichrome_irqs[] = { |
@@ -86,14 +85,24 @@ static maskarray_t via_unichrome_irqs[] = { | |||
86 | {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1, | 85 | {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1, |
87 | VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008} | 86 | VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008} |
88 | }; | 87 | }; |
89 | static int via_num_unichrome = sizeof(via_unichrome_irqs) / sizeof(maskarray_t); | 88 | static int via_num_unichrome = ARRAY_SIZE(via_unichrome_irqs); |
90 | static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1}; | 89 | static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1}; |
91 | 90 | ||
91 | |||
92 | static unsigned time_diff(struct timeval *now, struct timeval *then) | 92 | static unsigned time_diff(struct timeval *now, struct timeval *then) |
93 | { | 93 | { |
94 | return (now->tv_usec >= then->tv_usec) ? | 94 | return (now->tv_usec >= then->tv_usec) ? |
95 | now->tv_usec - then->tv_usec : | 95 | now->tv_usec - then->tv_usec : |
96 | 1000000 - (then->tv_usec - now->tv_usec); | 96 | 1000000 - (then->tv_usec - now->tv_usec); |
97 | } | ||
98 | |||
99 | u32 via_get_vblank_counter(struct drm_device *dev, int crtc) | ||
100 | { | ||
101 | drm_via_private_t *dev_priv = dev->dev_private; | ||
102 | if (crtc != 0) | ||
103 | return 0; | ||
104 | |||
105 | return atomic_read(&dev_priv->vbl_received); | ||
97 | } | 106 | } |
98 | 107 | ||
99 | irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) | 108 | irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) |
@@ -108,23 +117,22 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) | |||
108 | 117 | ||
109 | status = VIA_READ(VIA_REG_INTERRUPT); | 118 | status = VIA_READ(VIA_REG_INTERRUPT); |
110 | if (status & VIA_IRQ_VBLANK_PENDING) { | 119 | if (status & VIA_IRQ_VBLANK_PENDING) { |
111 | atomic_inc(&dev->vbl_received); | 120 | atomic_inc(&dev_priv->vbl_received); |
112 | if (!(atomic_read(&dev->vbl_received) & 0x0F)) { | 121 | if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) { |
113 | do_gettimeofday(&cur_vblank); | 122 | do_gettimeofday(&cur_vblank); |
114 | if (dev_priv->last_vblank_valid) { | 123 | if (dev_priv->last_vblank_valid) { |
115 | dev_priv->usec_per_vblank = | 124 | dev_priv->usec_per_vblank = |
116 | time_diff(&cur_vblank, | 125 | time_diff(&cur_vblank, |
117 | &dev_priv->last_vblank) >> 4; | 126 | &dev_priv->last_vblank) >> 4; |
118 | } | 127 | } |
119 | dev_priv->last_vblank = cur_vblank; | 128 | dev_priv->last_vblank = cur_vblank; |
120 | dev_priv->last_vblank_valid = 1; | 129 | dev_priv->last_vblank_valid = 1; |
121 | } | 130 | } |
122 | if (!(atomic_read(&dev->vbl_received) & 0xFF)) { | 131 | if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) { |
123 | DRM_DEBUG("US per vblank is: %u\n", | 132 | DRM_DEBUG("US per vblank is: %u\n", |
124 | dev_priv->usec_per_vblank); | 133 | dev_priv->usec_per_vblank); |
125 | } | 134 | } |
126 | DRM_WAKEUP(&dev->vbl_queue); | 135 | drm_handle_vblank(dev, 0); |
127 | drm_vbl_send_signals(dev); | ||
128 | handled = 1; | 136 | handled = 1; |
129 | } | 137 | } |
130 | 138 | ||
@@ -145,6 +153,7 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) | |||
145 | /* Acknowlege interrupts */ | 153 | /* Acknowlege interrupts */ |
146 | VIA_WRITE(VIA_REG_INTERRUPT, status); | 154 | VIA_WRITE(VIA_REG_INTERRUPT, status); |
147 | 155 | ||
156 | |||
148 | if (handled) | 157 | if (handled) |
149 | return IRQ_HANDLED; | 158 | return IRQ_HANDLED; |
150 | else | 159 | else |
@@ -163,31 +172,34 @@ static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv) | |||
163 | } | 172 | } |
164 | } | 173 | } |
165 | 174 | ||
166 | int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) | 175 | int via_enable_vblank(struct drm_device *dev, int crtc) |
167 | { | 176 | { |
168 | drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; | 177 | drm_via_private_t *dev_priv = dev->dev_private; |
169 | unsigned int cur_vblank; | 178 | u32 status; |
170 | int ret = 0; | ||
171 | 179 | ||
172 | DRM_DEBUG("\n"); | 180 | if (crtc != 0) { |
173 | if (!dev_priv) { | 181 | DRM_ERROR("%s: bad crtc %d\n", __func__, crtc); |
174 | DRM_ERROR("called with no initialization\n"); | ||
175 | return -EINVAL; | 182 | return -EINVAL; |
176 | } | 183 | } |
177 | 184 | ||
178 | viadrv_acknowledge_irqs(dev_priv); | 185 | status = VIA_READ(VIA_REG_INTERRUPT); |
186 | VIA_WRITE(VIA_REG_INTERRUPT, status & VIA_IRQ_VBLANK_ENABLE); | ||
187 | |||
188 | VIA_WRITE8(0x83d4, 0x11); | ||
189 | VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30); | ||
179 | 190 | ||
180 | /* Assume that the user has missed the current sequence number | 191 | return 0; |
181 | * by about a day rather than she wants to wait for years | 192 | } |
182 | * using vertical blanks... | 193 | |
183 | */ | 194 | void via_disable_vblank(struct drm_device *dev, int crtc) |
195 | { | ||
196 | drm_via_private_t *dev_priv = dev->dev_private; | ||
184 | 197 | ||
185 | DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, | 198 | VIA_WRITE8(0x83d4, 0x11); |
186 | (((cur_vblank = atomic_read(&dev->vbl_received)) - | 199 | VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30); |
187 | *sequence) <= (1 << 23))); | ||
188 | 200 | ||
189 | *sequence = cur_vblank; | 201 | if (crtc != 0) |
190 | return ret; | 202 | DRM_ERROR("%s: bad crtc %d\n", __func__, crtc); |
191 | } | 203 | } |
192 | 204 | ||
193 | static int | 205 | static int |
@@ -239,6 +251,7 @@ via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequenc | |||
239 | return ret; | 251 | return ret; |
240 | } | 252 | } |
241 | 253 | ||
254 | |||
242 | /* | 255 | /* |
243 | * drm_dma.h hooks | 256 | * drm_dma.h hooks |
244 | */ | 257 | */ |
@@ -292,23 +305,25 @@ void via_driver_irq_preinstall(struct drm_device * dev) | |||
292 | } | 305 | } |
293 | } | 306 | } |
294 | 307 | ||
295 | void via_driver_irq_postinstall(struct drm_device * dev) | 308 | int via_driver_irq_postinstall(struct drm_device *dev) |
296 | { | 309 | { |
297 | drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; | 310 | drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; |
298 | u32 status; | 311 | u32 status; |
299 | 312 | ||
300 | DRM_DEBUG("\n"); | 313 | DRM_DEBUG("via_driver_irq_postinstall\n"); |
301 | if (dev_priv) { | 314 | if (!dev_priv) |
302 | status = VIA_READ(VIA_REG_INTERRUPT); | 315 | return -EINVAL; |
303 | VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL | ||
304 | | dev_priv->irq_enable_mask); | ||
305 | 316 | ||
306 | /* Some magic, oh for some data sheets ! */ | 317 | drm_vblank_init(dev, 1); |
318 | status = VIA_READ(VIA_REG_INTERRUPT); | ||
319 | VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL | ||
320 | | dev_priv->irq_enable_mask); | ||
307 | 321 | ||
308 | VIA_WRITE8(0x83d4, 0x11); | 322 | /* Some magic, oh for some data sheets ! */ |
309 | VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30); | 323 | VIA_WRITE8(0x83d4, 0x11); |
324 | VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30); | ||
310 | 325 | ||
311 | } | 326 | return 0; |
312 | } | 327 | } |
313 | 328 | ||
314 | void via_driver_irq_uninstall(struct drm_device * dev) | 329 | void via_driver_irq_uninstall(struct drm_device * dev) |
@@ -339,9 +354,6 @@ int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv) | |||
339 | drm_via_irq_t *cur_irq = dev_priv->via_irqs; | 354 | drm_via_irq_t *cur_irq = dev_priv->via_irqs; |
340 | int force_sequence; | 355 | int force_sequence; |
341 | 356 | ||
342 | if (!dev->irq) | ||
343 | return -EINVAL; | ||
344 | |||
345 | if (irqwait->request.irq >= dev_priv->num_irqs) { | 357 | if (irqwait->request.irq >= dev_priv->num_irqs) { |
346 | DRM_ERROR("Trying to wait on unknown irq %d\n", | 358 | DRM_ERROR("Trying to wait on unknown irq %d\n", |
347 | irqwait->request.irq); | 359 | irqwait->request.irq); |
@@ -352,7 +364,8 @@ int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv) | |||
352 | 364 | ||
353 | switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) { | 365 | switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) { |
354 | case VIA_IRQ_RELATIVE: | 366 | case VIA_IRQ_RELATIVE: |
355 | irqwait->request.sequence += atomic_read(&cur_irq->irq_received); | 367 | irqwait->request.sequence += |
368 | atomic_read(&cur_irq->irq_received); | ||
356 | irqwait->request.type &= ~_DRM_VBLANK_RELATIVE; | 369 | irqwait->request.type &= ~_DRM_VBLANK_RELATIVE; |
357 | case VIA_IRQ_ABSOLUTE: | 370 | case VIA_IRQ_ABSOLUTE: |
358 | break; | 371 | break; |