OSDN Git Service

Convert to new ioctl interface between core DRM and device-specific module.
[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 addFlush2D(struct xgi_info * info);
33 static unsigned int get_batch_command(enum xgi_batch_type type);
34 static void triggerHWCommandList(struct xgi_info * info);
35 static void xgi_cmdlist_reset(struct xgi_info * info);
36
37 int xgi_cmdlist_initialize(struct xgi_info * info, size_t size)
38 {
39         struct xgi_mem_alloc mem_alloc = {
40                 .size = size,
41                 .owner = PCIE_2D,
42         };
43         int err;
44
45         err = xgi_pcie_alloc(info, &mem_alloc, 0);
46         if (err) {
47                 return err;
48         }
49
50         info->cmdring.ptr = xgi_find_pcie_virt(info, mem_alloc.hw_addr);
51         info->cmdring.size = mem_alloc.size;
52         info->cmdring.ring_hw_base = mem_alloc.hw_addr;
53         info->cmdring.ring_gart_base = mem_alloc.offset;
54         info->cmdring.last_ptr = NULL;
55         info->cmdring.ring_offset = 0;
56
57         return 0;
58 }
59
60
61 /**
62  * get_batch_command - Get the command ID for the current begin type.
63  * @type: Type of the current batch
64  *
65  * See section 3.2.2 "Begin" (page 15) of the 3D SPG.
66  * 
67  * This function assumes that @type is on the range [0,3].
68  */
69 unsigned int get_batch_command(enum xgi_batch_type type)
70 {
71         static const unsigned int ports[4] = {
72                 0x30 >> 2, 0x40 >> 2, 0x50 >> 2, 0x20 >> 2
73         };
74         
75         return ports[type];
76 }
77
78
79 int xgi_submit_cmdlist(struct drm_device * dev, void * data,
80                        struct drm_file * filp)
81 {
82         struct xgi_info *const info = dev->dev_private;
83         const struct xgi_cmd_info *const pCmdInfo =
84                 (struct xgi_cmd_info *) data;
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 (info->cmdring.last_ptr == NULL) {
96                 const unsigned int portOffset = BASE_3D_ENG + (cmd << 2);
97
98
99                 /* Enable PCI Trigger Mode
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                 dwWriteReg(info->mmio_map, portOffset,      begin[0]);
116                 dwWriteReg(info->mmio_map, portOffset +  4, begin[1]);
117                 dwWriteReg(info->mmio_map, portOffset +  8, begin[2]);
118                 dwWriteReg(info->mmio_map, portOffset + 12, begin[3]);
119         } else {
120                 DRM_DEBUG("info->cmdring.last_ptr != NULL\n");
121
122                 if (pCmdInfo->type == BTYPE_3D) {
123                         addFlush2D(info);
124                 }
125
126                 info->cmdring.last_ptr[1] = begin[1];
127                 info->cmdring.last_ptr[2] = begin[2];
128                 info->cmdring.last_ptr[3] = begin[3];
129                 wmb();
130                 info->cmdring.last_ptr[0] = begin[0];
131
132                 triggerHWCommandList(info);
133         }
134
135         info->cmdring.last_ptr = xgi_find_pcie_virt(info, pCmdInfo->hw_addr);
136         return 0;
137 }
138
139
140 /*
141     state:      0 - console
142                 1 - graphic
143                 2 - fb
144                 3 - logout
145 */
146 int xgi_state_change(struct xgi_info * info, unsigned int to, 
147                      unsigned int from)
148 {
149 #define STATE_CONSOLE   0
150 #define STATE_GRAPHIC   1
151 #define STATE_FBTERM    2
152 #define STATE_LOGOUT    3
153 #define STATE_REBOOT    4
154 #define STATE_SHUTDOWN  5
155
156         if ((from == STATE_GRAPHIC) && (to == STATE_CONSOLE)) {
157                 DRM_INFO("Leaving graphical mode (probably VT switch)\n");
158         } else if ((from == STATE_CONSOLE) && (to == STATE_GRAPHIC)) {
159                 DRM_INFO("Entering graphical mode (probably VT switch)\n");
160                 xgi_cmdlist_reset(info);
161         } else if ((from == STATE_GRAPHIC)
162                    && ((to == STATE_LOGOUT)
163                        || (to == STATE_REBOOT)
164                        || (to == STATE_SHUTDOWN))) {
165                 DRM_INFO("Leaving graphical mode (probably X shutting down)\n");
166         } else {
167                 DRM_ERROR("Invalid state change.\n");
168                 return -EINVAL;
169         }
170
171         return 0;
172 }
173
174
175 int xgi_state_change_ioctl(struct drm_device * dev, void * data,
176                            struct drm_file * filp)
177 {
178         struct xgi_state_info *const state =
179                 (struct xgi_state_info *) data;
180         struct xgi_info *info = dev->dev_private;
181
182
183         return xgi_state_change(info, state->_toState, state->_fromState);
184 }
185
186
187 void xgi_cmdlist_reset(struct xgi_info * info)
188 {
189         info->cmdring.last_ptr = NULL;
190         info->cmdring.ring_offset = 0;
191 }
192
193 void xgi_cmdlist_cleanup(struct xgi_info * info)
194 {
195         if (info->cmdring.ring_hw_base != 0) {
196                 xgi_pcie_free(info, info->cmdring.ring_gart_base, NULL);
197                 info->cmdring.ring_hw_base = 0;
198                 info->cmdring.ring_offset = 0;
199                 info->cmdring.size = 0;
200         }
201 }
202
203 static void triggerHWCommandList(struct xgi_info * info)
204 {
205         static unsigned int s_triggerID = 1;
206
207         dwWriteReg(info->mmio_map,
208                    BASE_3D_ENG + M2REG_PCI_TRIGGER_REGISTER_ADDRESS,
209                    0x05000000 + (0x0ffff & s_triggerID++));
210 }
211
212
213 static void addFlush2D(struct xgi_info * info)
214 {
215         u32 *flushBatchVirtAddr;
216         u32 flushBatchHWAddr;
217
218         /* check buf is large enough to contain a new flush batch */
219         if ((info->cmdring.ring_offset + 0x20) >= info->cmdring.size) {
220                 info->cmdring.ring_offset = 0;
221         }
222
223         flushBatchHWAddr = info->cmdring.ring_hw_base + info->cmdring.ring_offset;
224         flushBatchVirtAddr = info->cmdring.ptr 
225                 + (info->cmdring.ring_offset / 4);
226
227         /* not using memcpy for I assume the address is discrete */
228         *(flushBatchVirtAddr + 0) = 0x10000000;
229         *(flushBatchVirtAddr + 1) = 0x80000004; /* size = 0x04 dwords */
230         *(flushBatchVirtAddr + 2) = 0x00000000;
231         *(flushBatchVirtAddr + 3) = 0x00000000;
232         *(flushBatchVirtAddr + 4) = FLUSH_2D;
233         *(flushBatchVirtAddr + 5) = FLUSH_2D;
234         *(flushBatchVirtAddr + 6) = FLUSH_2D;
235         *(flushBatchVirtAddr + 7) = FLUSH_2D;
236
237         info->cmdring.last_ptr[1] = BEGIN_LINK_ENABLE_MASK + 0x08;
238         info->cmdring.last_ptr[2] = flushBatchHWAddr >> 4;
239         info->cmdring.last_ptr[3] = 0;
240         wmb();
241         info->cmdring.last_ptr[0] = (get_batch_command(BTYPE_CTRL) << 24) 
242                 | (BEGIN_VALID_MASK);
243
244         triggerHWCommandList(info);
245
246         info->cmdring.ring_offset += 0x20;
247         info->cmdring.last_ptr = flushBatchVirtAddr;
248 }