1 /****************************************************************************
2 * Copyright (C) 2003-2006 by XGI Technology, Taiwan.
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:
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.
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 ***************************************************************************/
30 #include "xgi_cmdlist.h"
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);
37 int xgi_cmdlist_initialize(struct xgi_info * info, size_t size)
39 struct xgi_mem_alloc mem_alloc = {
45 err = xgi_pcie_alloc(info, &mem_alloc, 0);
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;
62 * get_batch_command - Get the command ID for the current begin type.
63 * @type: Type of the current batch
65 * See section 3.2.2 "Begin" (page 15) of the 3D SPG.
67 * This function assumes that @type is on the range [0,3].
69 unsigned int get_batch_command(enum xgi_batch_type type)
71 static const unsigned int ports[4] = {
72 0x30 >> 2, 0x40 >> 2, 0x50 >> 2, 0x20 >> 2
79 int xgi_submit_cmdlist(struct drm_device * dev, void * data,
80 struct drm_file * filp)
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);
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;
95 if (info->cmdring.last_ptr == NULL) {
96 const unsigned int portOffset = BASE_3D_ENG + (cmd << 2);
99 /* Enable PCI Trigger Mode
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);
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);
113 /* Send PCI begin command
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]);
120 DRM_DEBUG("info->cmdring.last_ptr != NULL\n");
122 if (pCmdInfo->type == BTYPE_3D) {
126 info->cmdring.last_ptr[1] = begin[1];
127 info->cmdring.last_ptr[2] = begin[2];
128 info->cmdring.last_ptr[3] = begin[3];
130 info->cmdring.last_ptr[0] = begin[0];
132 triggerHWCommandList(info);
135 info->cmdring.last_ptr = xgi_find_pcie_virt(info, pCmdInfo->hw_addr);
146 int xgi_state_change(struct xgi_info * info, unsigned int to,
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
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");
167 DRM_ERROR("Invalid state change.\n");
175 int xgi_state_change_ioctl(struct drm_device * dev, void * data,
176 struct drm_file * filp)
178 struct xgi_state_info *const state =
179 (struct xgi_state_info *) data;
180 struct xgi_info *info = dev->dev_private;
183 return xgi_state_change(info, state->_toState, state->_fromState);
187 void xgi_cmdlist_reset(struct xgi_info * info)
189 info->cmdring.last_ptr = NULL;
190 info->cmdring.ring_offset = 0;
193 void xgi_cmdlist_cleanup(struct xgi_info * info)
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;
203 static void triggerHWCommandList(struct xgi_info * info)
205 static unsigned int s_triggerID = 1;
207 dwWriteReg(info->mmio_map,
208 BASE_3D_ENG + M2REG_PCI_TRIGGER_REGISTER_ADDRESS,
209 0x05000000 + (0x0ffff & s_triggerID++));
213 static void addFlush2D(struct xgi_info * info)
215 u32 *flushBatchVirtAddr;
216 u32 flushBatchHWAddr;
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;
223 flushBatchHWAddr = info->cmdring.ring_hw_base + info->cmdring.ring_offset;
224 flushBatchVirtAddr = info->cmdring.ptr
225 + (info->cmdring.ring_offset / 4);
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;
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;
241 info->cmdring.last_ptr[0] = (get_batch_command(BTYPE_CTRL) << 24)
242 | (BEGIN_VALID_MASK);
244 triggerHWCommandList(info);
246 info->cmdring.ring_offset += 0x20;
247 info->cmdring.last_ptr = flushBatchVirtAddr;