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 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);
40 * Graphic engine register (2d/3d) acessing interface
42 static inline void dwWriteReg(struct drm_map * map, u32 addr, u32 data)
45 DRM_INFO("mmio_map->handle = 0x%p, addr = 0x%x, data = 0x%x\n",
46 map->handle, addr, data);
48 DRM_WRITE32(map, addr, data);
52 int xgi_cmdlist_initialize(struct xgi_info * info, size_t size,
53 struct drm_file * filp)
55 struct xgi_mem_alloc mem_alloc = {
56 .location = XGI_MEMLOC_NON_LOCAL,
61 err = xgi_alloc(info, &mem_alloc, filp);
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;
77 * get_batch_command - Get the command ID for the current begin type.
78 * @type: Type of the current batch
80 * See section 3.2.2 "Begin" (page 15) of the 3D SPG.
82 * This function assumes that @type is on the range [0,3].
84 unsigned int get_batch_command(enum xgi_batch_type type)
86 static const unsigned int ports[4] = {
87 0x30 >> 2, 0x40 >> 2, 0x50 >> 2, 0x20 >> 2
94 int xgi_submit_cmdlist(struct drm_device * dev, void * data,
95 struct drm_file * filp)
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);
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;
110 if (info->cmdring.last_ptr == NULL) {
111 const unsigned int portOffset = BASE_3D_ENG + (cmd << 2);
114 /* Enable PCI Trigger Mode
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);
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);
128 /* Send PCI begin command
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]);
135 DRM_DEBUG("info->cmdring.last_ptr != NULL\n");
137 if (pCmdInfo->type == BTYPE_3D) {
138 xgi_emit_flush(info, false);
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]);
147 triggerHWCommandList(info);
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 */
164 int xgi_state_change(struct xgi_info * info, unsigned int to,
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
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");
185 DRM_ERROR("Invalid state change.\n");
193 int xgi_state_change_ioctl(struct drm_device * dev, void * data,
194 struct drm_file * filp)
196 struct xgi_state_info *const state =
197 (struct xgi_state_info *) data;
198 struct xgi_info *info = dev->dev_private;
201 return xgi_state_change(info, state->_toState, state->_fromState);
205 void xgi_cmdlist_reset(struct xgi_info * info)
207 info->cmdring.last_ptr = NULL;
208 info->cmdring.ring_offset = 0;
212 void xgi_cmdlist_cleanup(struct xgi_info * info)
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.
218 if (info->cmdring.last_ptr != NULL) {
219 xgi_emit_flush(info, false);
223 xgi_waitfor_pci_idle(info);
225 (void) memset(&info->cmdring, 0, sizeof(info->cmdring));
229 static void triggerHWCommandList(struct xgi_info * info)
231 static unsigned int s_triggerID = 1;
233 dwWriteReg(info->mmio_map,
234 BASE_3D_ENG + M2REG_PCI_TRIGGER_REGISTER_ADDRESS,
235 0x05000000 + (0x0ffff & s_triggerID++));
240 * Emit a flush to the CRTL command stream.
241 * @info XGI info structure
243 * This function assumes info->cmdring.ptr is non-NULL.
245 void xgi_emit_flush(struct xgi_info * info, bool stop)
247 const u32 flush_command[8] = {
249 | (BEGIN_BEGIN_IDENTIFICATION_MASK & info->next_sequence)),
250 BEGIN_LINK_ENABLE_MASK | (0x00004),
251 0x00000000, 0x00000000,
253 /* Flush the 2D engine with the default 32 clock delay.
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,
260 const unsigned int flush_size = sizeof(flush_command);
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;
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);
276 for (i = 0; i < (flush_size / 4); i++) {
277 batch_addr[i] = cpu_to_le32(flush_command[i]);
281 *batch_addr |= cpu_to_le32(BEGIN_STOP_STORE_CURRENT_POINTER_MASK);
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));
291 triggerHWCommandList(info);
293 info->cmdring.ring_offset += flush_size;
294 info->cmdring.last_ptr = batch_addr;
299 * Emit an empty command to the CRTL command stream.
300 * @info XGI info structure
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.
306 void xgi_emit_nop(struct xgi_info * info)
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));
316 triggerHWCommandList(info);
318 info->cmdring.last_ptr = NULL;
322 void xgi_emit_irq(struct xgi_info * info)
324 if (info->cmdring.last_ptr == NULL)
327 xgi_emit_flush(info, true);