Merge branch 'master' of ssh+git://git.freedesktop.org/git/mesa/drm into xgi-0-0-2
[profile/ivi/libdrm.git] / linux-core / xgi_misc.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
30 int xgi_ge_reset_ioctl(DRM_IOCTL_ARGS)
31 {
32         DRM_DEVICE;
33         struct xgi_info *info = dev->dev_private;
34
35         xgi_disable_ge(info);
36         xgi_enable_ge(info);
37
38         return 0;
39 }
40
41
42 /*
43  * irq functions
44  */
45 #define STALL_INTERRUPT_RESET_THRESHOLD 0xffff
46
47 static unsigned int s_invalid_begin = 0;
48
49 static bool xgi_validate_signal(volatile u8 *mmio_vbase)
50 {
51         volatile u32 *const ge_3d_status = 
52                 (volatile u32 *)(mmio_vbase + 0x2800);
53         const u32 old_ge_status = ge_3d_status[0x00];
54
55         if (old_ge_status & 0x001c0000) {
56                 u16 check;
57
58                 /* Check Read back status */
59                 *(mmio_vbase + 0x235c) = 0x80;
60                 check = *((volatile u16 *)(mmio_vbase + 0x2360));
61
62                 if ((check & 0x3f) != ((check & 0x3f00) >> 8)) {
63                         return FALSE;
64                 }
65
66                 /* Check RO channel */
67                 *(mmio_vbase + 0x235c) = 0x83;
68                 check = *((volatile u16 *)(mmio_vbase + 0x2360));
69                 if ((check & 0x0f) != ((check & 0xf0) >> 4)) {
70                         return FALSE;
71                 }
72
73                 /* Check RW channel */
74                 *(mmio_vbase + 0x235c) = 0x88;
75                 check = *((volatile u16 *)(mmio_vbase + 0x2360));
76                 if ((check & 0x0f) != ((check & 0xf0) >> 4)) {
77                         return FALSE;
78                 }
79
80                 /* Check RO channel outstanding */
81                 *(mmio_vbase + 0x235c) = 0x8f;
82                 check = *((volatile u16 *)(mmio_vbase + 0x2360));
83                 if (0 != (check & 0x3ff)) {
84                         return FALSE;
85                 }
86
87                 /* Check RW channel outstanding */
88                 *(mmio_vbase + 0x235c) = 0x90;
89                 check = *((volatile u16 *)(mmio_vbase + 0x2360));
90                 if (0 != (check & 0x3ff)) {
91                         return FALSE;
92                 }
93
94                 /* No pending PCIE request. GE stall. */
95         }
96
97         return TRUE;
98 }
99
100
101 static void xgi_ge_hang_reset(volatile u8 *mmio_vbase)
102 {
103         volatile u32 *const ge_3d_status =
104                 (volatile u32 *)(mmio_vbase + 0x2800);
105         int time_out = 0xffff;
106
107         *(mmio_vbase + 0xb057) = 8;
108         while (0 != (ge_3d_status[0x00] & 0xf0000000)) {
109                 while (0 != ((--time_out) & 0xfff)) 
110                         /* empty */ ;
111
112                 if (0 == time_out) {
113                         u8 old_3ce;
114                         u8 old_3cf;
115                         u8 old_index;
116                         u8 old_36;
117
118                         DRM_INFO("Can not reset back 0x%x!\n",
119                                  ge_3d_status[0x00]);
120
121                         *(mmio_vbase + 0xb057) = 0;
122
123                         /* Have to use 3x5.36 to reset. */
124                         /* Save and close dynamic gating */
125
126                         old_3ce = *(mmio_vbase + 0x3ce);
127                         *(mmio_vbase + 0x3ce) = 0x2a;
128                         old_3cf = *(mmio_vbase + 0x3cf);
129                         *(mmio_vbase + 0x3cf) = old_3cf & 0xfe;
130
131                         /* Reset GE */
132                         old_index = *(mmio_vbase + 0x3d4);
133                         *(mmio_vbase + 0x3d4) = 0x36;
134                         old_36 = *(mmio_vbase + 0x3d5);
135                         *(mmio_vbase + 0x3d5) = old_36 | 0x10;
136
137                         while (0 != ((--time_out) & 0xfff)) 
138                                 /* empty */ ;
139
140                         *(mmio_vbase + 0x3d5) = old_36;
141                         *(mmio_vbase + 0x3d4) = old_index;
142
143                         /* Restore dynamic gating */
144                         *(mmio_vbase + 0x3cf) = old_3cf; 
145                         *(mmio_vbase + 0x3ce) = old_3ce;
146                         break;
147                 }
148         }
149
150         *(mmio_vbase + 0xb057) = 0;
151 }
152
153         
154 bool xgi_ge_irq_handler(struct xgi_info * info)
155 {
156         volatile u8 *const mmio_vbase = info->mmio_map->handle;
157         volatile u32 *const ge_3d_status =
158                 (volatile u32 *)(mmio_vbase + 0x2800);
159         const u32 int_status = ge_3d_status[4];
160         bool is_support_auto_reset = FALSE;
161
162         /* Check GE on/off */
163         if (0 == (0xffffc0f0 & int_status)) {
164                 u32 old_pcie_cmd_fetch_Addr = ge_3d_status[0x0a];
165
166                 if (0 != (0x1000 & int_status)) {
167                         /* We got GE stall interrupt. 
168                          */
169                         ge_3d_status[0x04] = int_status | 0x04000000;
170
171                         if (is_support_auto_reset) {
172                                 static cycles_t last_tick;
173                                 static unsigned continue_int_count = 0;
174
175                                 /* OE II is busy. */
176
177                                 if (!xgi_validate_signal(mmio_vbase)) {
178                                         /* Nothing but skip. */
179                                 } else if (0 == continue_int_count++) {
180                                         last_tick = get_cycles();
181                                 } else {
182                                         const cycles_t new_tick = get_cycles();
183                                         if ((new_tick - last_tick) >
184                                             STALL_INTERRUPT_RESET_THRESHOLD) {
185                                                 continue_int_count = 0;
186                                         } else if (continue_int_count >= 3) {
187                                                 continue_int_count = 0;
188
189                                                 /* GE Hung up, need reset. */
190                                                 DRM_INFO("Reset GE!\n");
191
192                                                 xgi_ge_hang_reset(mmio_vbase);
193                                         }
194                                 }
195                         }
196                 } else if (0 != (0x1 & int_status)) {
197                         s_invalid_begin++;
198                         ge_3d_status[0x04] = (int_status & ~0x01) | 0x04000000;
199                 }
200
201                 return TRUE;
202         }
203
204         return FALSE;
205 }
206
207 bool xgi_crt_irq_handler(struct xgi_info * info)
208 {
209         bool ret = FALSE;
210         u8 save_3ce = DRM_READ8(info->mmio_map, 0x3ce);
211
212         if (IN3CFB(info->mmio_map, 0x37) & 0x01)        // CRT1 interrupt just happened
213         {
214                 u8 op3cf_3d;
215                 u8 op3cf_37;
216
217                 // What happened?
218                 op3cf_37 = IN3CFB(info->mmio_map, 0x37);
219
220                 // Clear CRT interrupt
221                 op3cf_3d = IN3CFB(info->mmio_map, 0x3d);
222                 OUT3CFB(info->mmio_map, 0x3d, (op3cf_3d | 0x04));
223                 OUT3CFB(info->mmio_map, 0x3d, (op3cf_3d & ~0x04));
224                 ret = TRUE;
225         }
226         DRM_WRITE8(info->mmio_map, 0x3ce, save_3ce);
227
228         return (ret);
229 }
230
231 bool xgi_dvi_irq_handler(struct xgi_info * info)
232 {
233         bool ret = FALSE;
234         const u8 save_3ce = DRM_READ8(info->mmio_map, 0x3ce);
235
236         if (IN3CFB(info->mmio_map, 0x38) & 0x20) {      // DVI interrupt just happened
237                 const u8 save_3x4 = DRM_READ8(info->mmio_map, 0x3d4);
238                 u8 op3cf_39;
239                 u8 op3cf_37;
240                 u8 op3x5_5a;
241
242                 // What happened?
243                 op3cf_37 = IN3CFB(info->mmio_map, 0x37);
244
245                 //Notify BIOS that DVI plug/unplug happened
246                 op3x5_5a = IN3X5B(info->mmio_map, 0x5a);
247                 OUT3X5B(info->mmio_map, 0x5a, op3x5_5a & 0xf7);
248
249                 DRM_WRITE8(info->mmio_map, 0x3d4, save_3x4);
250
251                 // Clear DVI interrupt
252                 op3cf_39 = IN3CFB(info->mmio_map, 0x39);
253                 OUT3C5B(info->mmio_map, 0x39, (op3cf_39 & ~0x01));      //Set 3cf.39 bit 0 to 0
254                 OUT3C5B(info->mmio_map, 0x39, (op3cf_39 | 0x01));       //Set 3cf.39 bit 0 to 1
255
256                 ret = TRUE;
257         }
258         DRM_WRITE8(info->mmio_map, 0x3ce, save_3ce);
259
260         return (ret);
261 }
262
263
264 void xgi_dump_register(struct xgi_info * info)
265 {
266         int i, j;
267         unsigned char temp;
268
269         // 0x3C5
270         printk("\r\n=====xgi_dump_register========0x%x===============\r\n",
271                0x3C5);
272
273         for (i = 0; i < 0x10; i++) {
274                 if (i == 0) {
275                         printk("%5x", i);
276                 } else {
277                         printk("%3x", i);
278                 }
279         }
280         printk("\r\n");
281
282         for (i = 0; i < 0x10; i++) {
283                 printk("%1x ", i);
284
285                 for (j = 0; j < 0x10; j++) {
286                         temp = IN3C5B(info->mmio_map, i * 0x10 + j);
287                         printk("%3x", temp);
288                 }
289                 printk("\r\n");
290         }
291
292         // 0x3D5
293         printk("\r\n====xgi_dump_register=========0x%x===============\r\n",
294                0x3D5);
295         for (i = 0; i < 0x10; i++) {
296                 if (i == 0) {
297                         printk("%5x", i);
298                 } else {
299                         printk("%3x", i);
300                 }
301         }
302         printk("\r\n");
303
304         for (i = 0; i < 0x10; i++) {
305                 printk("%1x ", i);
306
307                 for (j = 0; j < 0x10; j++) {
308                         temp = IN3X5B(info->mmio_map, i * 0x10 + j);
309                         printk("%3x", temp);
310                 }
311                 printk("\r\n");
312         }
313
314         // 0x3CF
315         printk("\r\n=========xgi_dump_register====0x%x===============\r\n",
316                0x3CF);
317         for (i = 0; i < 0x10; i++) {
318                 if (i == 0) {
319                         printk("%5x", i);
320                 } else {
321                         printk("%3x", i);
322                 }
323         }
324         printk("\r\n");
325
326         for (i = 0; i < 0x10; i++) {
327                 printk("%1x ", i);
328
329                 for (j = 0; j < 0x10; j++) {
330                         temp = IN3CFB(info->mmio_map, i * 0x10 + j);
331                         printk("%3x", temp);
332                 }
333                 printk("\r\n");
334         }
335
336         printk("\r\n=====xgi_dump_register======0x%x===============\r\n",
337                0xB000);
338         for (i = 0; i < 0x10; i++) {
339                 if (i == 0) {
340                         printk("%5x", i);
341                 } else {
342                         printk("%3x", i);
343                 }
344         }
345         printk("\r\n");
346
347         for (i = 0; i < 0x5; i++) {
348                 printk("%1x ", i);
349
350                 for (j = 0; j < 0x10; j++) {
351                         temp = DRM_READ8(info->mmio_map, 0xB000 + i * 0x10 + j);
352                         printk("%3x", temp);
353                 }
354                 printk("\r\n");
355         }
356
357         printk("\r\n==================0x%x===============\r\n", 0x2200);
358         for (i = 0; i < 0x10; i++) {
359                 if (i == 0) {
360                         printk("%5x", i);
361                 } else {
362                         printk("%3x", i);
363                 }
364         }
365         printk("\r\n");
366
367         for (i = 0; i < 0xB; i++) {
368                 printk("%1x ", i);
369
370                 for (j = 0; j < 0x10; j++) {
371                         temp = DRM_READ8(info->mmio_map, 0x2200 + i * 0x10 + j);
372                         printk("%3x", temp);
373                 }
374                 printk("\r\n");
375         }
376
377         printk("\r\n==================0x%x===============\r\n", 0x2300);
378         for (i = 0; i < 0x10; i++) {
379                 if (i == 0) {
380                         printk("%5x", i);
381                 } else {
382                         printk("%3x", i);
383                 }
384         }
385         printk("\r\n");
386
387         for (i = 0; i < 0x7; i++) {
388                 printk("%1x ", i);
389
390                 for (j = 0; j < 0x10; j++) {
391                         temp = DRM_READ8(info->mmio_map, 0x2300 + i * 0x10 + j);
392                         printk("%3x", temp);
393                 }
394                 printk("\r\n");
395         }
396
397         printk("\r\n==================0x%x===============\r\n", 0x2400);
398         for (i = 0; i < 0x10; i++) {
399                 if (i == 0) {
400                         printk("%5x", i);
401                 } else {
402                         printk("%3x", i);
403                 }
404         }
405         printk("\r\n");
406
407         for (i = 0; i < 0x10; i++) {
408                 printk("%1x ", i);
409
410                 for (j = 0; j < 0x10; j++) {
411                         temp = DRM_READ8(info->mmio_map, 0x2400 + i * 0x10 + j);
412                         printk("%3x", temp);
413                 }
414                 printk("\r\n");
415         }
416
417         printk("\r\n==================0x%x===============\r\n", 0x2800);
418         for (i = 0; i < 0x10; i++) {
419                 if (i == 0) {
420                         printk("%5x", i);
421                 } else {
422                         printk("%3x", i);
423                 }
424         }
425         printk("\r\n");
426
427         for (i = 0; i < 0x10; i++) {
428                 printk("%1x ", i);
429
430                 for (j = 0; j < 0x10; j++) {
431                         temp = DRM_READ8(info->mmio_map, 0x2800 + i * 0x10 + j);
432                         printk("%3x", temp);
433                 }
434                 printk("\r\n");
435         }
436 }
437
438
439 int xgi_dump_register_ioctl(DRM_IOCTL_ARGS)
440 {
441         DRM_DEVICE;
442         struct xgi_info *info = dev->dev_private;
443
444         xgi_dump_register(info);
445
446         return 0;
447 }
448
449
450 int xgi_restore_registers_ioctl(DRM_IOCTL_ARGS)
451 {
452         DRM_DEVICE;
453         struct xgi_info *info = dev->dev_private;
454
455         OUT3X5B(info->mmio_map, 0x13, 0);
456         OUT3X5B(info->mmio_map, 0x8b, 2);
457
458         return 0;
459 }
460
461 void xgi_waitfor_pci_idle(struct xgi_info * info)
462 {
463 #define WHOLD_GE_STATUS             0x2800
464 #define IDLE_MASK                   ~0x90200000
465
466         int idleCount = 0;
467         while (idleCount < 5) {
468                 if (DRM_READ32(info->mmio_map, WHOLD_GE_STATUS) & IDLE_MASK) {
469                         idleCount = 0;
470                 } else {
471                         idleCount++;
472                 }
473         }
474 }