5c31fa27900cb61866f13003e3720177656781d3
[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 struct xgi_cmdring_info s_cmdring;
35
36 static void addFlush2D(struct xgi_info * info);
37 static unsigned int get_batch_command(enum xgi_batch_type type);
38 static void triggerHWCommandList(struct xgi_info * info);
39 static void xgi_cmdlist_reset(void);
40
41 int xgi_cmdlist_initialize(struct xgi_info * info, size_t size)
42 {
43         struct xgi_mem_alloc mem_alloc = {
44                 .size = size,
45                 .owner = PCIE_2D,
46         };
47         int err;
48
49         err = xgi_pcie_alloc(info, &mem_alloc, 0);
50         if (err) {
51                 return err;
52         }
53
54         s_cmdring._cmdRingSize = mem_alloc.size;
55         s_cmdring._cmdRingBuffer = mem_alloc.hw_addr;
56         s_cmdring._cmdRingAllocOffset = mem_alloc.offset;
57         s_cmdring._lastBatchStartAddr = 0;
58         s_cmdring._cmdRingOffset = 0;
59
60         return 0;
61 }
62
63
64 /**
65  * get_batch_command - Get the command ID for the current begin type.
66  * @type: Type of the current batch
67  *
68  * See section 3.2.2 "Begin" (page 15) of the 3D SPG.
69  * 
70  * This function assumes that @type is on the range [0,3].
71  */
72 unsigned int get_batch_command(enum xgi_batch_type type)
73 {
74         static const unsigned int ports[4] = {
75                 0x30 >> 2, 0x40 >> 2, 0x50 >> 2, 0x20 >> 2
76         };
77         
78         return ports[type];
79 }
80
81
82 static void xgi_submit_cmdlist(struct xgi_info * info,
83                                const struct xgi_cmd_info * pCmdInfo)
84 {
85         const unsigned int cmd = get_batch_command(pCmdInfo->type);
86         u32 begin[4];
87
88
89         begin[0] = (cmd << 24) | BEGIN_VALID_MASK
90                 | (BEGIN_BEGIN_IDENTIFICATION_MASK & pCmdInfo->id);
91         begin[1] = BEGIN_LINK_ENABLE_MASK | pCmdInfo->size;
92         begin[2] = pCmdInfo->hw_addr >> 4;
93         begin[3] = 0;
94
95         if (s_cmdring._lastBatchStartAddr == 0) {
96                 const unsigned int portOffset = BASE_3D_ENG + (cmd << 2);
97
98
99                 /* Enable PCI Trigger Mode
100                  */
101                 DRM_INFO("Enable PCI Trigger Mode \n");
102
103                 dwWriteReg(info->mmio_map,
104                            BASE_3D_ENG + M2REG_AUTO_LINK_SETTING_ADDRESS,
105                            (M2REG_AUTO_LINK_SETTING_ADDRESS << 22) |
106                            M2REG_CLEAR_COUNTERS_MASK | 0x08 |
107                            M2REG_PCI_TRIGGER_MODE_MASK);
108
109                 dwWriteReg(info->mmio_map,
110                            BASE_3D_ENG + M2REG_AUTO_LINK_SETTING_ADDRESS,
111                            (M2REG_AUTO_LINK_SETTING_ADDRESS << 22) | 0x08 |
112                            M2REG_PCI_TRIGGER_MODE_MASK);
113
114
115                 /* Send PCI begin command
116                  */
117                 DRM_INFO("portOffset=%d, beginPort=%d\n",
118                          portOffset, cmd << 2);
119
120                 dwWriteReg(info->mmio_map, portOffset,      begin[0]);
121                 dwWriteReg(info->mmio_map, portOffset +  4, begin[1]);
122                 dwWriteReg(info->mmio_map, portOffset +  8, begin[2]);
123                 dwWriteReg(info->mmio_map, portOffset + 12, begin[3]);
124         } else {
125                 u32 *lastBatchVirtAddr;
126
127                 DRM_INFO("s_cmdring._lastBatchStartAddr != 0\n");
128
129                 if (pCmdInfo->type == BTYPE_3D) {
130                         addFlush2D(info);
131                 }
132
133                 lastBatchVirtAddr = 
134                         xgi_find_pcie_virt(info,
135                                            s_cmdring._lastBatchStartAddr);
136
137                 lastBatchVirtAddr[1] = begin[1];
138                 lastBatchVirtAddr[2] = begin[2];
139                 lastBatchVirtAddr[3] = begin[3];
140                 wmb();
141                 lastBatchVirtAddr[0] = begin[0];
142
143                 triggerHWCommandList(info);
144         }
145
146         s_cmdring._lastBatchStartAddr = pCmdInfo->hw_addr;
147         DRM_INFO("%s: exit\n", __func__);
148 }
149
150
151 int xgi_submit_cmdlist_ioctl(DRM_IOCTL_ARGS)
152 {
153         DRM_DEVICE;
154         struct xgi_cmd_info  cmd_list;
155         struct xgi_info *info = dev->dev_private;
156
157         DRM_COPY_FROM_USER_IOCTL(cmd_list, 
158                                  (struct xgi_cmd_info __user *) data,
159                                  sizeof(cmd_list));
160
161         if (cmd_list.type > BTYPE_CTRL) {
162                 return DRM_ERR(EINVAL);
163         }
164
165         xgi_submit_cmdlist(info, &cmd_list);
166         return 0;
167 }
168
169
170 /*
171     state:      0 - console
172                 1 - graphic
173                 2 - fb
174                 3 - logout
175 */
176 int xgi_state_change(struct xgi_info * info, unsigned int to, 
177                      unsigned int from)
178 {
179 #define STATE_CONSOLE   0
180 #define STATE_GRAPHIC   1
181 #define STATE_FBTERM    2
182 #define STATE_LOGOUT    3
183 #define STATE_REBOOT    4
184 #define STATE_SHUTDOWN  5
185
186         if ((from == STATE_GRAPHIC) && (to == STATE_CONSOLE)) {
187                 DRM_INFO("[kd] I see, now is to leaveVT\n");
188                 // stop to received batch
189         } else if ((from == STATE_CONSOLE) && (to == STATE_GRAPHIC)) {
190                 DRM_INFO("[kd] I see, now is to enterVT\n");
191                 xgi_cmdlist_reset();
192         } else if ((from == STATE_GRAPHIC)
193                    && ((to == STATE_LOGOUT)
194                        || (to == STATE_REBOOT)
195                        || (to == STATE_SHUTDOWN))) {
196                 DRM_INFO("[kd] I see, not is to exit from X\n");
197                 // stop to received batch
198         } else {
199                 DRM_ERROR("[kd] Should not happen\n");
200                 return DRM_ERR(EINVAL);
201         }
202
203         return 0;
204 }
205
206
207 int xgi_state_change_ioctl(DRM_IOCTL_ARGS)
208 {
209         DRM_DEVICE;
210         struct xgi_state_info  state;
211         struct xgi_info *info = dev->dev_private;
212
213         DRM_COPY_FROM_USER_IOCTL(state, (struct xgi_state_info __user *) data,
214                                  sizeof(state));
215
216         return xgi_state_change(info, state._toState, state._fromState);
217 }
218
219
220 void xgi_cmdlist_reset(void)
221 {
222         s_cmdring._lastBatchStartAddr = 0;
223         s_cmdring._cmdRingOffset = 0;
224 }
225
226 void xgi_cmdlist_cleanup(struct xgi_info * info)
227 {
228         if (s_cmdring._cmdRingBuffer != 0) {
229                 xgi_pcie_free(info, s_cmdring._cmdRingAllocOffset, NULL);
230                 s_cmdring._cmdRingBuffer = 0;
231                 s_cmdring._cmdRingOffset = 0;
232                 s_cmdring._cmdRingSize = 0;
233         }
234 }
235
236 static void triggerHWCommandList(struct xgi_info * info)
237 {
238         static unsigned int s_triggerID = 1;
239
240         dwWriteReg(info->mmio_map,
241                    BASE_3D_ENG + M2REG_PCI_TRIGGER_REGISTER_ADDRESS,
242                    0x05000000 + (0x0ffff & s_triggerID++));
243 }
244
245
246 static void addFlush2D(struct xgi_info * info)
247 {
248         u32 *flushBatchVirtAddr;
249         u32 flushBatchHWAddr;
250         u32 *lastBatchVirtAddr;
251
252         /* check buf is large enough to contain a new flush batch */
253         if ((s_cmdring._cmdRingOffset + 0x20) >= s_cmdring._cmdRingSize) {
254                 s_cmdring._cmdRingOffset = 0;
255         }
256
257         flushBatchHWAddr = s_cmdring._cmdRingBuffer + s_cmdring._cmdRingOffset;
258         flushBatchVirtAddr = xgi_find_pcie_virt(info, flushBatchHWAddr);
259
260         /* not using memcpy for I assume the address is discrete */
261         *(flushBatchVirtAddr + 0) = 0x10000000;
262         *(flushBatchVirtAddr + 1) = 0x80000004; /* size = 0x04 dwords */
263         *(flushBatchVirtAddr + 2) = 0x00000000;
264         *(flushBatchVirtAddr + 3) = 0x00000000;
265         *(flushBatchVirtAddr + 4) = FLUSH_2D;
266         *(flushBatchVirtAddr + 5) = FLUSH_2D;
267         *(flushBatchVirtAddr + 6) = FLUSH_2D;
268         *(flushBatchVirtAddr + 7) = FLUSH_2D;
269
270         // ASSERT(s_cmdring._lastBatchStartAddr != NULL);
271         lastBatchVirtAddr =
272                 xgi_find_pcie_virt(info, s_cmdring._lastBatchStartAddr);
273
274         lastBatchVirtAddr[1] = BEGIN_LINK_ENABLE_MASK + 0x08;
275         lastBatchVirtAddr[2] = flushBatchHWAddr >> 4;
276         lastBatchVirtAddr[3] = 0;
277         wmb();
278         lastBatchVirtAddr[0] = (get_batch_command(BTYPE_CTRL) << 24) 
279                 | (BEGIN_VALID_MASK);
280
281         triggerHWCommandList(info);
282
283         s_cmdring._cmdRingOffset += 0x20;
284         s_cmdring._lastBatchStartAddr = flushBatchHWAddr;
285 }