OSDN Git Service

nv50: context info for chipset 0xa0
[android-x86/external-libdrm.git] / linux-core / xgi_cmdlist.c
1 /****************************************************************************
2  * Copyright (C) 2003-2006 by XGI Technology, Taiwan.
3  *
4  * All Rights Reserved.
5  *
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 on the rights to use, copy, modify, merge,
10  * publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
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.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
21  * XGI AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  ***************************************************************************/
26
27 #include "xgi_drv.h"
28 #include "xgi_regs.h"
29 #include "xgi_misc.h"
30 #include "xgi_cmdlist.h"
31
32 static void xgi_emit_flush(struct xgi_info * info, bool stop);
33 static void xgi_emit_nop(struct xgi_info * info);
34 static unsigned int get_batch_command(enum xgi_batch_type type);
35 static void triggerHWCommandList(struct xgi_info * info);
36 static void xgi_cmdlist_reset(struct xgi_info * info);
37
38
39 /**
40  * Graphic engine register (2d/3d) acessing interface
41  */
42 static inline void dwWriteReg(struct drm_map * map, u32 addr, u32 data)
43 {
44 #ifdef XGI_MMIO_DEBUG
45         DRM_INFO("mmio_map->handle = 0x%p, addr = 0x%x, data = 0x%x\n",
46                  map->handle, addr, data);
47 #endif
48         DRM_WRITE32(map, addr, data);
49 }
50
51
52 int xgi_cmdlist_initialize(struct xgi_info * info, size_t size,
53                            struct drm_file * filp)
54 {
55         struct xgi_mem_alloc mem_alloc = {
56                 .location = XGI_MEMLOC_NON_LOCAL,
57                 .size = size,
58         };
59         int err;
60
61         err = xgi_alloc(info, &mem_alloc, filp);
62         if (err) {
63                 return err;
64         }
65
66         info->cmdring.ptr = xgi_find_pcie_virt(info, mem_alloc.hw_addr);
67         info->cmdring.size = mem_alloc.size;
68         info->cmdring.ring_hw_base = mem_alloc.hw_addr;
69         info->cmdring.last_ptr = NULL;
70         info->cmdring.ring_offset = 0;
71
72         return 0;
73 }
74
75
76 /**
77  * get_batch_command - Get the command ID for the current begin type.
78  * @type: Type of the current batch
79  *
80  * See section 3.2.2 "Begin" (page 15) of the 3D SPG.
81  *
82  * This function assumes that @type is on the range [0,3].
83  */
84 unsigned int get_batch_command(enum xgi_batch_type type)
85 {
86         static const unsigned int ports[4] = {
87                 0x30 >> 2, 0x40 >> 2, 0x50 >> 2, 0x20 >> 2
88         };
89
90         return ports[type];
91 }
92
93
94 int xgi_submit_cmdlist(struct drm_device * dev, void * data,
95                        struct drm_file * filp)
96 {
97         struct xgi_info *const info = dev->dev_private;
98         const struct xgi_cmd_info *const pCmdInfo =
99                 (struct xgi_cmd_info *) data;
100         const unsigned int cmd = get_batch_command(pCmdInfo->type);
101         u32 begin[4];
102
103
104         begin[0] = (cmd << 24) | BEGIN_VALID_MASK
105                 | (BEGIN_BEGIN_IDENTIFICATION_MASK & info->next_sequence);
106         begin[1] = BEGIN_LINK_ENABLE_MASK | pCmdInfo->size;
107         begin[2] = pCmdInfo->hw_addr >> 4;
108         begin[3] = 0;
109
110         if (info->cmdring.last_ptr == NULL) {
111                 const unsigned int portOffset = BASE_3D_ENG + (cmd << 2);
112
113
114                 /* Enable PCI Trigger Mode
115                  */
116                 dwWriteReg(info->mmio_map,
117                            BASE_3D_ENG + M2REG_AUTO_LINK_SETTING_ADDRESS,
118                            (M2REG_AUTO_LINK_SETTING_ADDRESS << 22) |
119                            M2REG_CLEAR_COUNTERS_MASK | 0x08 |
120                            M2REG_PCI_TRIGGER_MODE_MASK);
121
122                 dwWriteReg(info->mmio_map,
123                            BASE_3D_ENG + M2REG_AUTO_LINK_SETTING_ADDRESS,
124                            (M2REG_AUTO_LINK_SETTING_ADDRESS << 22) | 0x08 |
125                            M2REG_PCI_TRIGGER_MODE_MASK);
126
127
128                 /* Send PCI begin command
129                  */
130                 dwWriteReg(info->mmio_map, portOffset,      begin[0]);
131                 dwWriteReg(info->mmio_map, portOffset +  4, begin[1]);
132                 dwWriteReg(info->mmio_map, portOffset +  8, begin[2]);
133                 dwWriteReg(info->mmio_map, portOffset + 12, begin[3]);
134         } else {
135                 DRM_DEBUG("info->cmdring.last_ptr != NULL\n");
136
137                 if (pCmdInfo->type == BTYPE_3D) {
138                         xgi_emit_flush(info, false);
139                 }
140
141                 info->cmdring.last_ptr[1] = cpu_to_le32(begin[1]);
142                 info->cmdring.last_ptr[2] = cpu_to_le32(begin[2]);
143                 info->cmdring.last_ptr[3] = cpu_to_le32(begin[3]);
144                 DRM_WRITEMEMORYBARRIER();
145                 info->cmdring.last_ptr[0] = cpu_to_le32(begin[0]);
146
147                 triggerHWCommandList(info);
148         }
149
150         info->cmdring.last_ptr = xgi_find_pcie_virt(info, pCmdInfo->hw_addr);
151 #ifdef XGI_HAVE_FENCE
152         drm_fence_flush_old(info->dev, 0, info->next_sequence);
153 #endif /* XGI_HAVE_FENCE */
154         return 0;
155 }
156
157
158 /*
159     state:      0 - console
160                 1 - graphic
161                 2 - fb
162                 3 - logout
163 */
164 int xgi_state_change(struct xgi_info * info, unsigned int to,
165                      unsigned int from)
166 {
167 #define STATE_CONSOLE   0
168 #define STATE_GRAPHIC   1
169 #define STATE_FBTERM    2
170 #define STATE_LOGOUT    3
171 #define STATE_REBOOT    4
172 #define STATE_SHUTDOWN  5
173
174         if ((from == STATE_GRAPHIC) && (to == STATE_CONSOLE)) {
175                 DRM_INFO("Leaving graphical mode (probably VT switch)\n");
176         } else if ((from == STATE_CONSOLE) && (to == STATE_GRAPHIC)) {
177                 DRM_INFO("Entering graphical mode (probably VT switch)\n");
178                 xgi_cmdlist_reset(info);
179         } else if ((from == STATE_GRAPHIC)
180                    && ((to == STATE_LOGOUT)
181                        || (to == STATE_REBOOT)
182                        || (to == STATE_SHUTDOWN))) {
183                 DRM_INFO("Leaving graphical mode (probably X shutting down)\n");
184         } else {
185                 DRM_ERROR("Invalid state change.\n");
186                 return -EINVAL;
187         }
188
189         return 0;
190 }
191
192
193 int xgi_state_change_ioctl(struct drm_device * dev, void * data,
194                            struct drm_file * filp)
195 {
196         struct xgi_state_info *const state =
197                 (struct xgi_state_info *) data;
198         struct xgi_info *info = dev->dev_private;
199
200
201         return xgi_state_change(info, state->_toState, state->_fromState);
202 }
203
204
205 void xgi_cmdlist_reset(struct xgi_info * info)
206 {
207         info->cmdring.last_ptr = NULL;
208         info->cmdring.ring_offset = 0;
209 }
210
211
212 void xgi_cmdlist_cleanup(struct xgi_info * info)
213 {
214         if (info->cmdring.ring_hw_base != 0) {
215                 /* If command lists have been issued, terminate the command
216                  * list chain with a flush command.
217                  */
218                 if (info->cmdring.last_ptr != NULL) {
219                         xgi_emit_flush(info, false);
220                         xgi_emit_nop(info);
221                 }
222
223                 xgi_waitfor_pci_idle(info);
224
225                 (void) memset(&info->cmdring, 0, sizeof(info->cmdring));
226         }
227 }
228
229 static void triggerHWCommandList(struct xgi_info * info)
230 {
231         static unsigned int s_triggerID = 1;
232
233         dwWriteReg(info->mmio_map,
234                    BASE_3D_ENG + M2REG_PCI_TRIGGER_REGISTER_ADDRESS,
235                    0x05000000 + (0x0ffff & s_triggerID++));
236 }
237
238
239 /**
240  * Emit a flush to the CRTL command stream.
241  * @info XGI info structure
242  *
243  * This function assumes info->cmdring.ptr is non-NULL.
244  */
245 void xgi_emit_flush(struct xgi_info * info, bool stop)
246 {
247         const u32 flush_command[8] = {
248                 ((0x10 << 24)
249                  | (BEGIN_BEGIN_IDENTIFICATION_MASK & info->next_sequence)),
250                 BEGIN_LINK_ENABLE_MASK | (0x00004),
251                 0x00000000, 0x00000000,
252
253                 /* Flush the 2D engine with the default 32 clock delay.
254                  */
255                 M2REG_FLUSH_ENGINE_COMMAND | M2REG_FLUSH_2D_ENGINE_MASK,
256                 M2REG_FLUSH_ENGINE_COMMAND | M2REG_FLUSH_2D_ENGINE_MASK,
257                 M2REG_FLUSH_ENGINE_COMMAND | M2REG_FLUSH_2D_ENGINE_MASK,
258                 M2REG_FLUSH_ENGINE_COMMAND | M2REG_FLUSH_2D_ENGINE_MASK,
259         };
260         const unsigned int flush_size = sizeof(flush_command);
261         u32 *batch_addr;
262         u32 hw_addr;
263         unsigned int i;
264
265
266         /* check buf is large enough to contain a new flush batch */
267         if ((info->cmdring.ring_offset + flush_size) >= info->cmdring.size) {
268                 info->cmdring.ring_offset = 0;
269         }
270
271         hw_addr = info->cmdring.ring_hw_base
272                 + info->cmdring.ring_offset;
273         batch_addr = info->cmdring.ptr
274                 + (info->cmdring.ring_offset / 4);
275
276         for (i = 0; i < (flush_size / 4); i++) {
277                 batch_addr[i] = cpu_to_le32(flush_command[i]);
278         }
279
280         if (stop) {
281                 *batch_addr |= cpu_to_le32(BEGIN_STOP_STORE_CURRENT_POINTER_MASK);
282         }
283
284         info->cmdring.last_ptr[1] = cpu_to_le32(BEGIN_LINK_ENABLE_MASK | (flush_size / 4));
285         info->cmdring.last_ptr[2] = cpu_to_le32(hw_addr >> 4);
286         info->cmdring.last_ptr[3] = 0;
287         DRM_WRITEMEMORYBARRIER();
288         info->cmdring.last_ptr[0] = cpu_to_le32((get_batch_command(BTYPE_CTRL) << 24)
289                 | (BEGIN_VALID_MASK));
290
291         triggerHWCommandList(info);
292
293         info->cmdring.ring_offset += flush_size;
294         info->cmdring.last_ptr = batch_addr;
295 }
296
297
298 /**
299  * Emit an empty command to the CRTL command stream.
300  * @info XGI info structure
301  *
302  * This function assumes info->cmdring.ptr is non-NULL.  In addition, since
303  * this function emits a command that does not have linkage information,
304  * it sets info->cmdring.ptr to NULL.
305  */
306 void xgi_emit_nop(struct xgi_info * info)
307 {
308         info->cmdring.last_ptr[1] = cpu_to_le32(BEGIN_LINK_ENABLE_MASK
309                 | (BEGIN_BEGIN_IDENTIFICATION_MASK & info->next_sequence));
310         info->cmdring.last_ptr[2] = 0;
311         info->cmdring.last_ptr[3] = 0;
312         DRM_WRITEMEMORYBARRIER();
313         info->cmdring.last_ptr[0] = cpu_to_le32((get_batch_command(BTYPE_CTRL) << 24)
314                 | (BEGIN_VALID_MASK));
315
316         triggerHWCommandList(info);
317
318         info->cmdring.last_ptr = NULL;
319 }
320
321
322 void xgi_emit_irq(struct xgi_info * info)
323 {
324         if (info->cmdring.last_ptr == NULL)
325                 return;
326
327         xgi_emit_flush(info, true);
328 }