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