Make s_cmdring a field in the xgi_info structure instead of a global.
[platform/upstream/libdrm.git] / linux-core / xgi_cmdlist.c
1
2 /****************************************************************************
3  * Copyright (C) 2003-2006 by XGI Technology, Taiwan.                   
4  *                                                                                                                                                      *
5  * All Rights Reserved.                                                                                                         *
6  *                                                                                                                                                      *
7  * Permission is hereby granted, free of charge, to any person obtaining
8  * a copy of this software and associated documentation files (the      
9  * "Software"), to deal in the Software without restriction, including  
10  * without limitation on the rights to use, copy, modify, merge,        
11  * publish, distribute, sublicense, and/or sell copies of the Software, 
12  * and to permit persons to whom the Software is furnished to do so,    
13  * subject to the following conditions:                                 
14  *                                                                                                                                                      *
15  * The above copyright notice and this permission notice (including the 
16  * next paragraph) shall be included in all copies or substantial       
17  * portions of the Software.                                            
18  *                                                                                                                                                      *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,      
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF   
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND                
22  * NON-INFRINGEMENT.  IN NO EVENT SHALL XGI AND/OR                      
23  * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,           
24  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,           
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER                        
26  * DEALINGS IN THE SOFTWARE.                                                                                            
27  ***************************************************************************/
28
29 #include "xgi_drv.h"
30 #include "xgi_regs.h"
31 #include "xgi_misc.h"
32 #include "xgi_cmdlist.h"
33
34 static void addFlush2D(struct xgi_info * info);
35 static unsigned int get_batch_command(enum xgi_batch_type type);
36 static void triggerHWCommandList(struct xgi_info * info);
37 static void xgi_cmdlist_reset(struct xgi_info * info);
38
39 int xgi_cmdlist_initialize(struct xgi_info * info, size_t size)
40 {
41         struct xgi_mem_alloc mem_alloc = {
42                 .size = size,
43                 .owner = PCIE_2D,
44         };
45         int err;
46
47         err = xgi_pcie_alloc(info, &mem_alloc, 0);
48         if (err) {
49                 return err;
50         }
51
52         info->cmdring._cmdRingSize = mem_alloc.size;
53         info->cmdring._cmdRingBuffer = mem_alloc.hw_addr;
54         info->cmdring._cmdRingAllocOffset = mem_alloc.offset;
55         info->cmdring._lastBatchStartAddr = 0;
56         info->cmdring._cmdRingOffset = 0;
57
58         return 0;
59 }
60
61
62 /**
63  * get_batch_command - Get the command ID for the current begin type.
64  * @type: Type of the current batch
65  *
66  * See section 3.2.2 "Begin" (page 15) of the 3D SPG.
67  * 
68  * This function assumes that @type is on the range [0,3].
69  */
70 unsigned int get_batch_command(enum xgi_batch_type type)
71 {
72         static const unsigned int ports[4] = {
73                 0x30 >> 2, 0x40 >> 2, 0x50 >> 2, 0x20 >> 2
74         };
75         
76         return ports[type];
77 }
78
79
80 static void xgi_submit_cmdlist(struct xgi_info * info,
81                                const struct xgi_cmd_info * pCmdInfo)
82 {
83         const unsigned int cmd = get_batch_command(pCmdInfo->type);
84         u32 begin[4];
85
86
87         begin[0] = (cmd << 24) | BEGIN_VALID_MASK
88                 | (BEGIN_BEGIN_IDENTIFICATION_MASK & pCmdInfo->id);
89         begin[1] = BEGIN_LINK_ENABLE_MASK | pCmdInfo->size;
90         begin[2] = pCmdInfo->hw_addr >> 4;
91         begin[3] = 0;
92
93         if (info->cmdring._lastBatchStartAddr == 0) {
94                 const unsigned int portOffset = BASE_3D_ENG + (cmd << 2);
95
96
97                 /* Enable PCI Trigger Mode
98                  */
99                 DRM_INFO("Enable PCI Trigger Mode \n");
100
101                 dwWriteReg(info->mmio_map,
102                            BASE_3D_ENG + M2REG_AUTO_LINK_SETTING_ADDRESS,
103                            (M2REG_AUTO_LINK_SETTING_ADDRESS << 22) |
104                            M2REG_CLEAR_COUNTERS_MASK | 0x08 |
105                            M2REG_PCI_TRIGGER_MODE_MASK);
106
107                 dwWriteReg(info->mmio_map,
108                            BASE_3D_ENG + M2REG_AUTO_LINK_SETTING_ADDRESS,
109                            (M2REG_AUTO_LINK_SETTING_ADDRESS << 22) | 0x08 |
110                            M2REG_PCI_TRIGGER_MODE_MASK);
111
112
113                 /* Send PCI begin command
114                  */
115                 DRM_INFO("portOffset=%d, beginPort=%d\n",
116                          portOffset, cmd << 2);
117
118                 dwWriteReg(info->mmio_map, portOffset,      begin[0]);
119                 dwWriteReg(info->mmio_map, portOffset +  4, begin[1]);
120                 dwWriteReg(info->mmio_map, portOffset +  8, begin[2]);
121                 dwWriteReg(info->mmio_map, portOffset + 12, begin[3]);
122         } else {
123                 u32 *lastBatchVirtAddr;
124
125                 DRM_INFO("info->cmdring._lastBatchStartAddr != 0\n");
126
127                 if (pCmdInfo->type == BTYPE_3D) {
128                         addFlush2D(info);
129                 }
130
131                 lastBatchVirtAddr = 
132                         xgi_find_pcie_virt(info,
133                                            info->cmdring._lastBatchStartAddr);
134
135                 lastBatchVirtAddr[1] = begin[1];
136                 lastBatchVirtAddr[2] = begin[2];
137                 lastBatchVirtAddr[3] = begin[3];
138                 wmb();
139                 lastBatchVirtAddr[0] = begin[0];
140
141                 triggerHWCommandList(info);
142         }
143
144         info->cmdring._lastBatchStartAddr = pCmdInfo->hw_addr;
145         DRM_INFO("%s: exit\n", __func__);
146 }
147
148
149 int xgi_submit_cmdlist_ioctl(DRM_IOCTL_ARGS)
150 {
151         DRM_DEVICE;
152         struct xgi_cmd_info  cmd_list;
153         struct xgi_info *info = dev->dev_private;
154
155         DRM_COPY_FROM_USER_IOCTL(cmd_list, 
156                                  (struct xgi_cmd_info __user *) data,
157                                  sizeof(cmd_list));
158
159         if (cmd_list.type > BTYPE_CTRL) {
160                 return DRM_ERR(EINVAL);
161         }
162
163         xgi_submit_cmdlist(info, &cmd_list);
164         return 0;
165 }
166
167
168 /*
169     state:      0 - console
170                 1 - graphic
171                 2 - fb
172                 3 - logout
173 */
174 int xgi_state_change(struct xgi_info * info, unsigned int to, 
175                      unsigned int from)
176 {
177 #define STATE_CONSOLE   0
178 #define STATE_GRAPHIC   1
179 #define STATE_FBTERM    2
180 #define STATE_LOGOUT    3
181 #define STATE_REBOOT    4
182 #define STATE_SHUTDOWN  5
183
184         if ((from == STATE_GRAPHIC) && (to == STATE_CONSOLE)) {
185                 DRM_INFO("[kd] I see, now is to leaveVT\n");
186                 // stop to received batch
187         } else if ((from == STATE_CONSOLE) && (to == STATE_GRAPHIC)) {
188                 DRM_INFO("[kd] I see, now is to enterVT\n");
189                 xgi_cmdlist_reset(info);
190         } else if ((from == STATE_GRAPHIC)
191                    && ((to == STATE_LOGOUT)
192                        || (to == STATE_REBOOT)
193                        || (to == STATE_SHUTDOWN))) {
194                 DRM_INFO("[kd] I see, not is to exit from X\n");
195                 // stop to received batch
196         } else {
197                 DRM_ERROR("[kd] Should not happen\n");
198                 return DRM_ERR(EINVAL);
199         }
200
201         return 0;
202 }
203
204
205 int xgi_state_change_ioctl(DRM_IOCTL_ARGS)
206 {
207         DRM_DEVICE;
208         struct xgi_state_info  state;
209         struct xgi_info *info = dev->dev_private;
210
211         DRM_COPY_FROM_USER_IOCTL(state, (struct xgi_state_info __user *) data,
212                                  sizeof(state));
213
214         return xgi_state_change(info, state._toState, state._fromState);
215 }
216
217
218 void xgi_cmdlist_reset(struct xgi_info * info)
219 {
220         info->cmdring._lastBatchStartAddr = 0;
221         info->cmdring._cmdRingOffset = 0;
222 }
223
224 void xgi_cmdlist_cleanup(struct xgi_info * info)
225 {
226         if (info->cmdring._cmdRingBuffer != 0) {
227                 xgi_pcie_free(info, info->cmdring._cmdRingAllocOffset, NULL);
228                 info->cmdring._cmdRingBuffer = 0;
229                 info->cmdring._cmdRingOffset = 0;
230                 info->cmdring._cmdRingSize = 0;
231         }
232 }
233
234 static void triggerHWCommandList(struct xgi_info * info)
235 {
236         static unsigned int s_triggerID = 1;
237
238         dwWriteReg(info->mmio_map,
239                    BASE_3D_ENG + M2REG_PCI_TRIGGER_REGISTER_ADDRESS,
240                    0x05000000 + (0x0ffff & s_triggerID++));
241 }
242
243
244 static void addFlush2D(struct xgi_info * info)
245 {
246         u32 *flushBatchVirtAddr;
247         u32 flushBatchHWAddr;
248         u32 *lastBatchVirtAddr;
249
250         /* check buf is large enough to contain a new flush batch */
251         if ((info->cmdring._cmdRingOffset + 0x20) >= info->cmdring._cmdRingSize) {
252                 info->cmdring._cmdRingOffset = 0;
253         }
254
255         flushBatchHWAddr = info->cmdring._cmdRingBuffer + info->cmdring._cmdRingOffset;
256         flushBatchVirtAddr = xgi_find_pcie_virt(info, flushBatchHWAddr);
257
258         /* not using memcpy for I assume the address is discrete */
259         *(flushBatchVirtAddr + 0) = 0x10000000;
260         *(flushBatchVirtAddr + 1) = 0x80000004; /* size = 0x04 dwords */
261         *(flushBatchVirtAddr + 2) = 0x00000000;
262         *(flushBatchVirtAddr + 3) = 0x00000000;
263         *(flushBatchVirtAddr + 4) = FLUSH_2D;
264         *(flushBatchVirtAddr + 5) = FLUSH_2D;
265         *(flushBatchVirtAddr + 6) = FLUSH_2D;
266         *(flushBatchVirtAddr + 7) = FLUSH_2D;
267
268         // ASSERT(info->cmdring._lastBatchStartAddr != NULL);
269         lastBatchVirtAddr =
270                 xgi_find_pcie_virt(info, info->cmdring._lastBatchStartAddr);
271
272         lastBatchVirtAddr[1] = BEGIN_LINK_ENABLE_MASK + 0x08;
273         lastBatchVirtAddr[2] = flushBatchHWAddr >> 4;
274         lastBatchVirtAddr[3] = 0;
275         wmb();
276         lastBatchVirtAddr[0] = (get_batch_command(BTYPE_CTRL) << 24) 
277                 | (BEGIN_VALID_MASK);
278
279         triggerHWCommandList(info);
280
281         info->cmdring._cmdRingOffset += 0x20;
282         info->cmdring._lastBatchStartAddr = flushBatchHWAddr;
283 }