Remove FIFO and object handling out of the DDX. This commit makes the DDX dependant...
[nouveau] / src / nv_dma.c
1
2 #include "nv_include.h"
3 #include "nvreg.h"
4
5 CARD32 NVDmaCreateDMAObject(NVPtr pNv, int target, CARD32 base_address, CARD32 size, int access)
6 {
7         drm_nouveau_dma_object_init_t dma;
8         CARD32 object;
9
10         dma.instance = &object;
11         dma.access   = access;
12         dma.target   = target;
13         dma.size     = size;
14         dma.offset   = base_address;
15         if (target == NV_DMA_TARGET_AGP)
16                 dma.offset += pNv->agpPhysical;
17         drmCommandWriteRead(pNv->drm_fd, DRM_NOUVEAU_DMA_OBJECT_INIT, &dma, sizeof(dma));
18
19     return object;
20 }
21
22 /*
23    A DMA notifier is a DMA object that references a small (32 byte it
24    seems, we use 256 for saftey) memory area that will be used by the HW to give feedback
25    about a DMA operation.
26 */
27 CARD32 NVDmaCreateNotifier(NVPtr pNv, int target, CARD32 base_address)
28 {
29     return NVDmaCreateDMAObject(pNv, target, base_address, 0x100, NV_DMA_ACCES_RW);
30 }
31
32 /*
33   How do we wait for DMA completion (by notifiers) ?
34
35    Either repeatedly read the notifier address and wait until it changes,
36    or enable a 'wakeup' interrupt by writing NOTIFY_WRITE_LE_AWAKEN into
37    the 'notify' field of the object in the channel.  My guess is that 
38    this causes an interrupt in PGRAPH/NOTIFY as soon as the transfer is
39    completed.  Clients probably can use poll on the nv* devices to get this 
40    event.  All this is a guess.  I don't know any details, and I have not
41    tested is.  Also, I have no idea how the 'nvdriver' reacts if it gets 
42    notify events that are not registered.
43
44    Writing NV_NOTIFY_WRITE_LE_AWAKEN into the 'Notify' field of an object
45    in a channel really causes an interrupt in the PGRAPH engine.  Thus
46    we can determine whether a DMA transfer has finished in the interrupt
47    handler.
48
49    We can't use interrupts in user land, so we do the simple polling approach.
50    The method returns FALSE in case of an error.
51 */
52 Bool NVDmaWaitForNotifier(NVPtr pNv, int target, CARD32 base_address)
53 {
54     volatile U032 *n;
55     unsigned char *notifier = (target == NV_DMA_TARGET_AGP)
56                               ? pNv->agpMemory
57                               : pNv->FbBase;
58     notifier += base_address;
59     n = (volatile U032 *)notifier;
60     NVDEBUG("NVDmaWaitForNotifier @%p", n);
61     while (1) {
62         U032 a = n[0];
63         U032 b = n[1];
64         U032 c = n[2];
65         U032 status = n[3];
66         NVDEBUG("status: n[0]=%x, n[1]=%x, n[2]=%x, n[3]=%x\n", a, b, c, status);
67         if (status == 0xffffffff)
68             continue;
69         if (!status)
70             break;
71         if (status & 0xffff)
72             return FALSE;
73     }
74     return TRUE;
75 }
76
77 void NVDmaCreateContextObject(NVPtr pNv, int handle, int class, CARD32 flags,
78                               CARD32 dma_in, CARD32 dma_out, CARD32 dma_notifier)
79 {
80         drm_nouveau_object_init_t cto;
81     CARD32 nv_flags0 = 0, nv_flags1 = 0, nv_flags2 = 0;
82     
83     if (pNv->Architecture >= NV_ARCH_40) {
84         if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND)
85             nv_flags0 |= 0x02080000;
86         else if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY)
87             nv_flags0 |= 0x02080000;
88         if (flags & NV_DMA_CONTEXT_FLAGS_CLIP_ENABLE)
89             nv_flags0 |= 0x00020000;
90 #if X_BYTE_ORDER == X_BIG_ENDIAN
91         if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
92             nv_flags1 |= 0x01000000;
93         nv_flags2 |= 0x01000000;
94 #else
95         if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
96             nv_flags1 |= 0x02000000;
97 #endif
98     } else {
99         if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND)
100             nv_flags0 |= 0x01008000;
101         else if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY)
102             nv_flags0 |= 0x01018000;
103         if (flags & NV_DMA_CONTEXT_FLAGS_CLIP_ENABLE)
104             nv_flags0 |= 0x00002000;
105 #if X_BYTE_ORDER == X_BIG_ENDIAN
106         nv_flags0 |= 0x00080000;
107         if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
108             nv_flags1 |= 0x00000001;
109 #else
110         if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
111             nv_flags1 |= 0x00000002;
112 #endif
113     }
114
115         cto.handle = handle;
116         cto.class  = class;
117         cto.flags0 = nv_flags0;
118         cto.flags1 = nv_flags1;
119         cto.flags2 = nv_flags2;
120         cto.dma_in       = dma_in;
121         cto.dma_out      = dma_out;
122         cto.dma_notifier = dma_notifier;
123         drmCommandWrite(pNv->drm_fd, DRM_NOUVEAU_OBJECT_INIT, &cto, sizeof(cto));
124 }
125                            
126 Bool NVInitDma(ScrnInfoPtr pScrn)
127 {
128     NVPtr pNv = NVPTR(pScrn);
129     CARD32 dma_fb;
130 #ifdef XF86DRI
131     CARD32 dma_agp;
132     CARD32 dma_notifier;
133 #endif
134         drm_nouveau_fifo_init_t fifo_init;
135         unsigned int *fifo_regs, *fifo_cmdbuf;
136         int fifo;
137         int i;
138
139         if (!NVDRIScreenInit(pScrn))
140                 return FALSE;
141
142         fifo_init.fifo_num = &fifo;
143         if (drmCommandWriteRead(pNv->drm_fd, DRM_NOUVEAU_FIFO_INIT, &fifo_init, sizeof(fifo_init)) != 0) {
144                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not initialise kernel module\n");
145                 return FALSE;
146         }
147
148     dma_fb = NVDmaCreateDMAObject(pNv, NV_DMA_TARGET_VIDMEM, 0, pNv->FbMapSize, NV_DMA_ACCES_RW);
149     
150     NVDmaCreateContextObject (pNv, NvContextSurfaces,
151                               (pNv->Architecture >= NV_ARCH_10) ? NV10_CONTEXT_SURFACES_2D : NV4_SURFACE,
152                               NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND,
153                               dma_fb, dma_fb, 0);
154     NVDmaCreateContextObject (pNv, NvRop,
155                               NV_ROP5_SOLID, 
156                               NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND,
157                               0, 0, 0);
158     NVDmaCreateContextObject (pNv, NvImagePattern,
159                               NV4_IMAGE_PATTERN, 
160                               NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND|NV_DMA_CONTEXT_FLAGS_MONO,
161                               0, 0, 0);
162     NVDmaCreateContextObject (pNv, NvClipRectangle,
163                               NV_IMAGE_BLACK_RECTANGLE, 
164                               NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND,
165                               0, 0, 0);
166     NVDmaCreateContextObject (pNv, NvSolidLine,
167                               NV4_RENDER_SOLID_LIN, 
168                               NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND|NV_DMA_CONTEXT_FLAGS_CLIP_ENABLE,
169                               0, 0, 0);
170     NVDmaCreateContextObject (pNv, NvImageBlit,
171                               pNv->WaitVSyncPossible ? NV12_IMAGE_BLIT : NV_IMAGE_BLIT,
172                               NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND, 
173                               dma_fb, dma_fb, 0);
174     NVDmaCreateContextObject (pNv, NvRectangle,
175                               NV4_GDI_RECTANGLE_TEXT, 
176                               NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND|NV_DMA_CONTEXT_FLAGS_MONO, 
177                               0, 0, 0);
178     NVDmaCreateContextObject (pNv, NvScaledImage,
179                               NV_SCALED_IMAGE_FROM_MEMORY, 
180                               NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY, 
181                               dma_fb, dma_fb, 0);
182
183 #ifdef XF86DRI
184     if (NVInitAGP(pScrn) && pNv->agpMemory) {
185
186         dma_agp = NVDmaCreateDMAObject(pNv, NV_DMA_TARGET_AGP, 0x10000, pNv->agpSize - 0x10000,
187                                        NV_DMA_ACCES_RW);
188         dma_notifier = NVDmaCreateNotifier(pNv, NV_DMA_TARGET_AGP, 0);
189         
190         NVDmaCreateContextObject (pNv, NvGraphicsToAGP,
191                                   NV_MEMORY_TO_MEMORY_FORMAT,
192                                   0,
193                                   dma_fb, dma_agp, dma_notifier);
194         
195         NVDmaCreateContextObject (pNv, NvAGPToGraphics,
196                                   NV_MEMORY_TO_MEMORY_FORMAT,
197                                   0,
198                                   dma_agp, dma_fb, dma_notifier);
199     }
200 #endif
201
202         fifo_regs   = pNv->FIFO;
203         fifo_cmdbuf = pNv->dmaBase;
204
205         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using FIFO %d\n", fifo);
206         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "FIFO control registers: %p\n", fifo_regs);
207         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "DMA command buffer    : %p\n", fifo_cmdbuf);
208         return TRUE;
209 }