2 * Copyright (C) 2006 Ben Skeggs.
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 * Ben Skeggs <darktama@iinet.net.au>
35 #include "nouveau_drm.h"
36 #include "nouveau_drv.h"
37 #include "nouveau_reg.h"
39 void nouveau_irq_preinstall(drm_device_t *dev)
41 drm_nouveau_private_t *dev_priv = dev->dev_private;
43 DRM_DEBUG("IRQ: preinst\n");
45 /* Disable/Clear PFIFO interrupts */
46 NV_WRITE(NV03_PFIFO_INTR_EN_0, 0);
47 NV_WRITE(NV03_PMC_INTR_0, 0xFFFFFFFF);
48 /* Disable/Clear PGRAPH interrupts */
49 if (dev_priv->card_type<NV_40)
50 NV_WRITE(NV03_PGRAPH_INTR_EN, 0);
52 NV_WRITE(NV40_PGRAPH_INTR_EN, 0);
53 NV_WRITE(NV03_PGRAPH_INTR, 0xFFFFFFFF);
55 /* Disable/Clear CRTC0/1 interrupts */
56 NV_WRITE(NV_CRTC0_INTEN, 0);
57 NV_WRITE(NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK);
58 NV_WRITE(NV_CRTC1_INTEN, 0);
59 NV_WRITE(NV_CRTC1_INTSTAT, NV_CRTC_INTR_VBLANK);
62 NV_WRITE(NV03_PMC_INTR_EN_0, 0);
65 void nouveau_irq_postinstall(drm_device_t *dev)
67 drm_nouveau_private_t *dev_priv = dev->dev_private;
69 DRM_DEBUG("IRQ: postinst\n");
71 /* Enable PFIFO error reporting */
72 NV_WRITE(NV03_PFIFO_INTR_EN_0 ,
73 NV_PFIFO_INTR_CACHE_ERROR |
74 NV_PFIFO_INTR_RUNOUT |
75 NV_PFIFO_INTR_RUNOUT_OVERFLOW |
76 NV_PFIFO_INTR_DMA_PUSHER |
77 NV_PFIFO_INTR_DMA_PT |
78 NV_PFIFO_INTR_SEMAPHORE |
79 NV_PFIFO_INTR_ACQUIRE_TIMEOUT
81 NV_WRITE(NV03_PMC_INTR_0, 0xFFFFFFFF);
83 /* Enable PGRAPH interrupts */
84 if (dev_priv->card_type<NV_40)
85 NV_WRITE(NV03_PGRAPH_INTR_EN,
86 NV_PGRAPH_INTR_NOTIFY |
87 NV_PGRAPH_INTR_MISSING_HW |
88 NV_PGRAPH_INTR_CONTEXT_SWITCH |
89 NV_PGRAPH_INTR_BUFFER_NOTIFY |
93 NV_WRITE(NV40_PGRAPH_INTR_EN,
94 NV_PGRAPH_INTR_NOTIFY |
95 NV_PGRAPH_INTR_MISSING_HW |
96 NV_PGRAPH_INTR_CONTEXT_SWITCH |
97 NV_PGRAPH_INTR_BUFFER_NOTIFY |
100 NV_WRITE(NV03_PGRAPH_INTR, 0xFFFFFFFF);
103 /* Enable CRTC0/1 interrupts */
104 NV_WRITE(NV_CRTC0_INTEN, NV_CRTC_INTR_VBLANK);
105 NV_WRITE(NV_CRTC1_INTEN, NV_CRTC_INTR_VBLANK);
109 NV_WRITE(NV03_PMC_INTR_EN_0, NV_PMC_INTR_EN_0_MASTER_ENABLE);
112 void nouveau_irq_uninstall(drm_device_t *dev)
114 drm_nouveau_private_t *dev_priv = dev->dev_private;
116 DRM_DEBUG("IRQ: uninst\n");
118 /* Disable PFIFO interrupts */
119 NV_WRITE(NV03_PFIFO_INTR_EN_0, 0);
120 /* Disable PGRAPH interrupts */
121 if (dev_priv->card_type<NV_40)
122 NV_WRITE(NV03_PGRAPH_INTR_EN, 0);
124 NV_WRITE(NV40_PGRAPH_INTR_EN, 0);
126 /* Disable CRTC0/1 interrupts */
127 NV_WRITE(NV_CRTC0_INTEN, 0);
128 NV_WRITE(NV_CRTC1_INTEN, 0);
131 NV_WRITE(NV03_PMC_INTR_EN_0, 0);
134 static void nouveau_fifo_irq_handler(drm_device_t *dev)
136 uint32_t status, chmode, chstat, channel;
137 drm_nouveau_private_t *dev_priv = dev->dev_private;
139 status = NV_READ(NV03_PMC_INTR_0);
142 chmode = NV_READ(NV04_PFIFO_MODE);
143 chstat = NV_READ(NV04_PFIFO_DMA);
144 channel=NV_READ(NV03_PFIFO_CACHE1_PUSH1)&(nouveau_fifo_number(dev)-1);
146 DRM_DEBUG("NV: PFIFO interrupt! Channel=%d, INTSTAT=0x%08x/MODE=0x%08x/PEND=0x%08x\n", channel, status, chmode, chstat);
148 if (status & NV_PFIFO_INTR_CACHE_ERROR) {
149 uint32_t c1get, c1method, c1data;
151 DRM_ERROR("NV: PFIFO error interrupt\n");
153 c1get = NV_READ(NV03_PFIFO_CACHE1_GET) >> 2;
154 if (dev_priv->card_type < NV_40) {
155 /* Untested, so it may not work.. */
156 c1method = NV_READ(NV04_PFIFO_CACHE1_METHOD(c1get));
157 c1data = NV_READ(NV04_PFIFO_CACHE1_DATA(c1get));
159 c1method = NV_READ(NV40_PFIFO_CACHE1_METHOD(c1get));
160 c1data = NV_READ(NV40_PFIFO_CACHE1_DATA(c1get));
163 DRM_ERROR("NV: Channel %d/%d - Method 0x%04x, Data 0x%08x\n",
164 channel, (c1method >> 13) & 7,
165 c1method & 0x1ffc, c1data
168 status &= ~NV_PFIFO_INTR_CACHE_ERROR;
169 NV_WRITE(NV03_PMC_INTR_0, NV_PFIFO_INTR_CACHE_ERROR);
172 if (status & NV_PFIFO_INTR_DMA_PUSHER) {
173 DRM_INFO("NV: PFIFO DMA pusher interrupt\n");
175 status &= ~NV_PFIFO_INTR_DMA_PUSHER;
176 NV_WRITE(NV03_PMC_INTR_0, NV_PFIFO_INTR_DMA_PUSHER);
178 NV_WRITE(NV04_PFIFO_CACHE1_DMA_STATE, 0x00000000);
179 if (NV_READ(NV04_PFIFO_CACHE1_DMA_PUT)!=NV_READ(NV04_PFIFO_CACHE1_DMA_GET))
181 uint32_t getval=NV_READ(NV04_PFIFO_CACHE1_DMA_GET)+4;
182 NV_WRITE(NV04_PFIFO_CACHE1_DMA_GET,getval);
187 DRM_INFO("NV: unknown PFIFO interrupt. status=0x%08x\n", status);
189 NV_WRITE(NV03_PMC_INTR_0, status);
192 NV_WRITE(NV03_PMC_INTR_0, NV_PMC_INTR_0_PFIFO_PENDING);
196 static void nouveau_nv04_context_switch(drm_device_t *dev)
198 drm_nouveau_private_t *dev_priv = dev->dev_private;
201 NV_WRITE(NV04_PGRAPH_FIFO,0x0);
202 channel=NV_READ(NV03_PFIFO_CACHE1_PUSH1)&(nouveau_fifo_number(dev)-1);
203 //DRM_INFO("raw PFIFO_CACH1_PHS1 reg is %x\n",NV_READ(NV03_PFIFO_CACHE1_PUSH1));
204 //DRM_INFO("currently on channel %d\n",channel);
205 for (i=0;i<nouveau_fifo_number(dev);i++)
206 if ((dev_priv->fifos[i].used)&&(i!=channel)) {
207 uint32_t put,get,pending;
208 //put=NV_READ(dev_priv->ramfc_offset+i*32);
209 //get=NV_READ(dev_priv->ramfc_offset+4+i*32);
210 put=NV_READ(NV03_FIFO_REGS_DMAPUT(i));
211 get=NV_READ(NV03_FIFO_REGS_DMAGET(i));
212 pending=NV_READ(NV04_PFIFO_DMA);
213 //DRM_INFO("Channel %d (put/get %x/%x)\n",i,put,get);
214 /* mark all pending channels as such */
215 if ((put!=get)&!(pending&(1<<i)))
218 NV_WRITE(NV04_PFIFO_DMA,pending);
222 nouveau_wait_for_idle(dev);
225 /* 2-channel commute */
226 // NV_WRITE(NV03_PFIFO_CACHE1_PUSH1,channel|0x100);
231 // dev_priv->cur_fifo=channel;
232 NV_WRITE(NV04_PFIFO_NEXT_CHANNEL,channel|0x100);
234 //NV_WRITE(NV03_PFIFO_CACHE1_PUSH1,max|0x100);
235 //NV_WRITE(0x2050,max|0x100);
237 NV_WRITE(NV04_PGRAPH_FIFO,0x1);
242 static void nouveau_pgraph_irq_handler(drm_device_t *dev)
245 drm_nouveau_private_t *dev_priv = dev->dev_private;
247 status = NV_READ(NV03_PGRAPH_INTR);
251 if (status & NV_PGRAPH_INTR_NOTIFY) {
252 uint32_t nsource, nstatus, instance, notify;
253 DRM_DEBUG("NV: PGRAPH notify interrupt\n");
255 nstatus = NV_READ(0x00400104);
256 nsource = NV_READ(0x00400108);
257 DRM_DEBUG("nsource:0x%08x\tnstatus:0x%08x\n", nsource, nstatus);
259 instance = NV_READ(0x00400158);
260 notify = NV_READ(0x00400150) >> 16;
261 DRM_DEBUG("instance:0x%08x\tnotify:0x%08x\n", nsource, nstatus);
263 status &= ~NV_PGRAPH_INTR_NOTIFY;
264 NV_WRITE(NV03_PGRAPH_INTR, NV_PGRAPH_INTR_NOTIFY);
267 if (status & NV_PGRAPH_INTR_BUFFER_NOTIFY) {
268 uint32_t nsource, nstatus, instance, notify;
269 DRM_DEBUG("NV: PGRAPH buffer notify interrupt\n");
271 nstatus = NV_READ(0x00400104);
272 nsource = NV_READ(0x00400108);
273 DRM_DEBUG("nsource:0x%08x\tnstatus:0x%08x\n", nsource, nstatus);
275 instance = NV_READ(0x00400158);
276 notify = NV_READ(0x00400150) >> 16;
277 DRM_DEBUG("instance:0x%08x\tnotify:0x%08x\n", instance, notify);
279 status &= ~NV_PGRAPH_INTR_BUFFER_NOTIFY;
280 NV_WRITE(NV03_PGRAPH_INTR, NV_PGRAPH_INTR_BUFFER_NOTIFY);
283 if (status & NV_PGRAPH_INTR_MISSING_HW) {
284 DRM_ERROR("NV: PGRAPH missing hw interrupt\n");
286 status &= ~NV_PGRAPH_INTR_MISSING_HW;
287 NV_WRITE(NV03_PGRAPH_INTR, NV_PGRAPH_INTR_MISSING_HW);
290 if (status & NV_PGRAPH_INTR_ERROR) {
291 uint32_t nsource, nstatus, instance;
294 uint32_t method, subc, data;
296 DRM_ERROR("NV: PGRAPH error interrupt\n");
298 nstatus = NV_READ(0x00400104);
299 nsource = NV_READ(0x00400108);
300 DRM_ERROR("nsource:0x%08x\tnstatus:0x%08x\n", nsource, nstatus);
302 instance = NV_READ(0x00400158);
303 DRM_ERROR("instance:0x%08x\n", instance);
305 address = NV_READ(0x400704);
306 data = NV_READ(0x400708);
307 channel = (address >> 20) & 0x1F;
308 subc = (address >> 16) & 0x7;
309 method = address & 0x1FFC;
310 DRM_DEBUG("NV: 0x400704 = 0x%08x\n", address);
311 DRM_ERROR("NV: Channel %d/%d (class 0x%04x) -"
312 "Method 0x%04x, Data 0x%08x\n",
314 NV_READ(0x400160+subc*4) & 0xFFFF,
318 status &= ~NV_PGRAPH_INTR_ERROR;
319 NV_WRITE(NV03_PGRAPH_INTR, NV_PGRAPH_INTR_ERROR);
322 if (status & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
323 uint32_t channel=NV_READ(NV03_PFIFO_CACHE1_PUSH1)&(nouveau_fifo_number(dev)-1);
324 DRM_INFO("NV: PGRAPH context switch interrupt channel %x\n",channel);
325 switch(dev_priv->card_type)
329 nouveau_nv04_context_switch(dev);
332 nouveau_nv10_context_switch(dev);
336 nouveau_nv20_context_switch(dev);
339 DRM_INFO("NV: Context switch not implemented\n");
343 status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
344 NV_WRITE(NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
348 DRM_INFO("NV: Unknown PGRAPH interrupt! STAT=0x%08x\n", status);
349 NV_WRITE(NV03_PGRAPH_INTR, status);
352 NV_WRITE(NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING);
355 static void nouveau_crtc_irq_handler(drm_device_t *dev, int crtc)
357 drm_nouveau_private_t *dev_priv = dev->dev_private;
359 NV_WRITE(NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK);
363 NV_WRITE(NV_CRTC1_INTSTAT, NV_CRTC_INTR_VBLANK);
367 irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS)
369 drm_device_t *dev = (drm_device_t*)arg;
370 drm_nouveau_private_t *dev_priv = dev->dev_private;
373 status = NV_READ(NV03_PMC_INTR_0);
377 DRM_DEBUG("PMC INTSTAT: 0x%08x\n", status);
379 if (status & NV_PMC_INTR_0_PFIFO_PENDING) {
380 nouveau_fifo_irq_handler(dev);
381 status &= ~NV_PMC_INTR_0_PFIFO_PENDING;
383 if (status & NV_PMC_INTR_0_PGRAPH_PENDING) {
384 nouveau_pgraph_irq_handler(dev);
385 status &= ~NV_PMC_INTR_0_PGRAPH_PENDING;
387 if (status & NV_PMC_INTR_0_CRTCn_PENDING) {
388 nouveau_crtc_irq_handler(dev, (status>>24)&3);
389 status &= ~NV_PMC_INTR_0_CRTCn_PENDING;
393 DRM_ERROR("Unhandled PMC INTR status bits 0x%08x\n", status);