nv_bios indentation
[nouveau] / src / nv_bios.c
1 /*
2  * Copyright 2005-2006 Erik Waling
3  * Copyright 2006 Stephane Marchesin
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
20  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23
24 #include "nv_include.h"
25 #include "nvreg.h"
26 #include <byteswap.h>
27 #define DEBUGLEVEL 6
28 /*#define PERFORM_WRITE*/
29
30 /* TODO: 
31  *       * PLL algorithms.
32  */
33
34 typedef struct {
35         Bool execute;
36         Bool repeat;
37 } init_exec_t;
38
39 typedef struct {
40         uint8_t *data;
41         unsigned int length;
42
43         uint16_t init_script_tbls_ptr;
44         uint16_t macro_index_tbl_ptr;
45         uint16_t macro_tbl_ptr;
46         uint16_t condition_tbl_ptr;
47         uint16_t io_condition_tbl_ptr;
48         uint16_t io_flag_condition_tbl_ptr;
49         uint16_t init_function_tbl_ptr;
50
51         uint16_t fptablepointer;
52         uint16_t fpxlatetableptr;
53         uint16_t lvdsmanufacturerpointer;
54         uint16_t fpxlatemanufacturertableptr;
55 } bios_t;
56
57 static Bool nv_cksum(const uint8_t *data, unsigned int offset, unsigned int length)
58 {
59         /* there's a few checksums in the BIOS, so here's a generic checking function */
60         int i;
61         uint8_t sum = 0;
62
63         for (i = 0; i < length; i++)
64                 sum += data[offset + i];
65
66         if (sum)
67                 return TRUE;
68
69         return FALSE;
70 }
71
72 static Bool NVValidVBIOS(ScrnInfoPtr pScrn, const uint8_t *data)
73 {
74         /* check for BIOS signature */
75         if (!(data[0] == 0x55 && data[1] == 0xAA)) {
76                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
77                            "... BIOS signature not found\n");
78                 return FALSE;
79         }
80
81         if (nv_cksum(data, 0, data[2] * 512)) {
82                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
83                            "... BIOS checksum invalid\n");
84                 /* probably ought to set a do_not_execute flag for table parsing here,
85                  * assuming most BIOSen are valid */
86         } else
87                 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "... appears to be valid\n");
88
89         return TRUE;
90 }
91
92 static void NVShadowVBIOS_PROM(ScrnInfoPtr pScrn, uint8_t *data)
93 {
94         NVPtr pNv = NVPTR(pScrn);
95         int i;
96
97         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
98                    "Attempting to locate BIOS image in PROM\n");
99
100         /* enable ROM access */
101         nvWriteMC(pNv, 0x1850, 0x0);
102         for (i = 0; i < NV_PROM_SIZE; i++) {
103                 /* according to nvclock, we need that to work around a 6600GT/6800LE bug */
104                 data[i] = pNv->PROM[i];
105                 data[i] = pNv->PROM[i];
106                 data[i] = pNv->PROM[i];
107                 data[i] = pNv->PROM[i];
108                 data[i] = pNv->PROM[i];
109         }
110         /* disable ROM access */
111         nvWriteMC(pNv, 0x1850, 0x1);
112 }
113
114 #define NV_PRAMIN_ROM_OFFSET 0x00700000
115
116 static void NVShadowVBIOS_PRAMIN(ScrnInfoPtr pScrn, uint32_t *data)
117 {
118         NVPtr pNv = NVPTR(pScrn);
119         const uint32_t *pramin = (void*)&pNv->REGS[NV_PRAMIN_ROM_OFFSET/4];
120         uint32_t old_bar0_pramin = 0;
121
122         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
123                    "Attempting to locate BIOS image in PRAMIN\n");
124
125         if (pNv->Architecture >= NV_ARCH_50) {
126                 uint32_t vbios_vram;
127
128                 vbios_vram = (pNv->REGS[0x619f04/4] & ~0xff) << 8;
129                 if (!vbios_vram) {
130                         vbios_vram = pNv->REGS[0x1700/4] << 16;
131                         vbios_vram += 0xf0000;
132                 }
133
134                 old_bar0_pramin = pNv->REGS[0x1700/4];
135                 pNv->REGS[0x1700/4] = vbios_vram >> 16;
136         }
137
138         memcpy(data, pramin, NV_PROM_SIZE);
139
140         if (pNv->Architecture >= NV_ARCH_50) {
141                 pNv->REGS[0x1700/4] = old_bar0_pramin;
142         }
143 }
144
145 static Bool NVShadowVBIOS(ScrnInfoPtr pScrn, uint32_t *data)
146 {
147         NVShadowVBIOS_PROM(pScrn, (uint8_t *)data);
148         if (NVValidVBIOS(pScrn, (uint8_t *)data))
149                 return TRUE;
150
151         NVShadowVBIOS_PRAMIN(pScrn, data);
152         if (NVValidVBIOS(pScrn, (uint8_t *)data))
153                 return TRUE;
154
155         return FALSE;
156 }
157
158 typedef struct {
159         char* name;
160         uint8_t id;
161         int length;
162         int length_offset;
163         int length_multiplier;
164         Bool (*handler)(ScrnInfoPtr pScrn, bios_t *, uint16_t, init_exec_t *);
165 } init_tbl_entry_t;
166
167 typedef struct {
168         uint8_t id[2];
169         uint16_t length;
170         uint16_t offset;
171 } bit_entry_t;
172
173 static void parse_init_table(ScrnInfoPtr pScrn, bios_t *bios, unsigned int offset, init_exec_t *iexec);
174
175 #define MACRO_INDEX_SIZE        2
176 #define MACRO_SIZE              8
177 #define CONDITION_SIZE          12
178 #define IO_FLAG_CONDITION_SIZE  9 
179
180 void still_alive()
181 {
182         sync();
183 //      usleep(200000);
184 }
185
186 static int nv_valid_reg(uint32_t reg)
187 {
188         #define WITHIN(x,y,z) ((x>=y)&&(x<y+z))
189         if (WITHIN(reg,NV_PRAMIN_OFFSET,NV_PRAMIN_SIZE))
190                 return 1;
191         if (WITHIN(reg,NV_PCRTC0_OFFSET,NV_PCRTC0_SIZE))
192                 return 1;
193         if (WITHIN(reg,NV_PRAMDAC0_OFFSET,NV_PRAMDAC0_SIZE))
194                 return 1;
195         if (WITHIN(reg,NV_PFB_OFFSET,NV_PFB_SIZE))
196                 return 1;
197         if (WITHIN(reg,NV_PFIFO_OFFSET,NV_PFIFO_SIZE))
198                 return 1;
199         if (WITHIN(reg,NV_PGRAPH_OFFSET,NV_PGRAPH_SIZE))
200                 return 1;
201         if (WITHIN(reg,NV_PEXTDEV_OFFSET,NV_PEXTDEV_SIZE))
202                 return 1;
203         if (WITHIN(reg,NV_PTIMER_OFFSET,NV_PTIMER_SIZE))
204                 return 1;
205         if (WITHIN(reg,NV_PVIDEO_OFFSET,NV_PVIDEO_SIZE))
206                 return 1;
207         if (WITHIN(reg,NV_PMC_OFFSET,NV_PMC_SIZE))
208                 return 1;
209         if (WITHIN(reg,NV_FIFO_OFFSET,NV_FIFO_SIZE))
210                 return 1;
211         if (WITHIN(reg,NV_PCIO0_OFFSET,NV_PCIO0_SIZE))
212                 return 1;
213         if (WITHIN(reg,NV_PDIO0_OFFSET,NV_PDIO0_SIZE))
214                 return 1;
215         if (WITHIN(reg,NV_PVIO_OFFSET,NV_PVIO_SIZE))
216                 return 1;
217         if (WITHIN(reg,NV_PROM_OFFSET,NV_PROM_SIZE))
218                 return 1;
219         if (WITHIN(reg,NV_PRAMIN_ROM_OFFSET,NV_PROM_SIZE))
220                 return 1;
221         #undef WITHIN
222         return 0;
223 }
224
225 static void nv32_rd(ScrnInfoPtr pScrn, uint32_t reg, uint32_t *data)
226 {
227         NVPtr pNv = NVPTR(pScrn);
228
229         *data = pNv->REGS[reg/4];
230         if (DEBUGLEVEL >= 6)
231                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
232                            "    Read:  Reg: 0x%08X, Data: 0x%08X\n", reg, *data);
233 }
234
235 static int nv32_wr(ScrnInfoPtr pScrn, uint32_t reg, uint32_t data)
236 {
237         if (DEBUGLEVEL >= 8) {
238                 uint32_t tmp;
239                 nv32_rd(pScrn, reg, &tmp);
240         }
241         if (DEBUGLEVEL >= 6)
242                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
243                            "    Write: Reg: 0x%08X, Data: 0x%08X\n", reg, data);
244         if (!nv_valid_reg(reg)) {
245                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
246                            "========= unknown reg 0x%X ==========\n", reg);
247                 return 0;
248         }
249 #ifdef PERFORM_WRITE
250         still_alive();
251         NVPtr pNv = NVPTR(pScrn);
252         pNv->REGS[reg/4] = data;
253 #endif
254         return 1;
255 }
256
257 static void nv_port_rd(ScrnInfoPtr pScrn, uint16_t port, uint8_t index, uint8_t *data, int head)
258 {
259         NVPtr pNv = NVPTR(pScrn);
260         volatile uint8_t *ptr = head ? pNv->PCIO1 : pNv->PCIO0;
261
262         VGA_WR08(ptr, port, index);
263         *data = VGA_RD08(ptr, port + 1);
264
265         if (DEBUGLEVEL >= 6)
266                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
267                            "    Indexed read:  Port: 0x%04X, Index: 0x%02X, Head: 0x%02X, Data: 0x%02X\n",
268                            port, index, head, *data);
269 }
270
271 static void nv_port_wr(ScrnInfoPtr pScrn, uint16_t port, uint8_t index, uint8_t data, int head)
272 {
273         NVPtr pNv = NVPTR(pScrn);
274         volatile uint8_t *ptr = head ? pNv->PCIO1 : pNv->PCIO0;
275
276         if (DEBUGLEVEL >= 8) {
277                 uint8_t tmp;
278                 nv_port_rd(pScrn, port, index, &tmp, head);
279         }
280         if (DEBUGLEVEL >= 6)
281                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
282                            "    Indexed write: Port: 0x%04X, Index: 0x%02X, Head: 0x%02X, Data: 0x%02X\n",
283                            port, index, head, data);
284 #ifdef PERFORM_WRITE
285         still_alive();
286         VGA_WR08(ptr, port, index);
287         VGA_WR08(ptr, port + 1, data);
288 #endif
289 }
290
291 static void nv_set_crtc_index(ScrnInfoPtr pScrn, CARD8 index)
292 {
293 #ifdef PERFORM_WRITE
294         xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "nv_set_crtc_index index 0x%X\n",index);
295         still_alive();
296         NVPtr pNv = NVPTR(pScrn);
297         volatile CARD8 *ptr = pNv->cur_head ? pNv->PCIO1 : pNv->PCIO0;
298         VGA_WR08(ptr, 0x3D4, index);
299 #endif
300 }
301
302 static CARD8 nv_rd_crtc_data(ScrnInfoPtr pScrn)
303 {
304         NVPtr pNv = NVPTR(pScrn);
305         volatile CARD8 *ptr = pNv->cur_head ? pNv->PCIO1 : pNv->PCIO0;
306         return VGA_RD08(ptr, 0x3D5);
307 }
308
309 static void nv_wr_crtc_data(ScrnInfoPtr pScrn, CARD8 val)
310 {
311 #ifdef PERFORM_WRITE
312         xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "nv_wr_crtc_data value 0x%X\n",val);
313         still_alive();
314         NVPtr pNv = NVPTR(pScrn);
315         volatile CARD8 *ptr = pNv->cur_head ? pNv->PCIO1 : pNv->PCIO0;
316         VGA_WR08(ptr, 0x3D5, val);
317 #endif
318 }
319
320 static Bool init_prog(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
321 {
322         /* INIT_PROG   opcode: 0x31
323          * 
324          * offset      (8  bit): opcode
325          * offset + 1  (32 bit): reg
326          * offset + 5  (32 bit): and mask
327          * offset + 9  (8  bit): shift right
328          * offset + 10 (8  bit): number of configurations
329          * offset + 11 (32 bit): register
330          * offset + 15 (32 bit): configuration 1
331          * ...
332          * 
333          * Starting at offset + 15 there are "number of configurations"
334          * 32 bit values. To find out which configuration value to use
335          * read "CRTC reg" on the CRTC controller with index "CRTC index"
336          * and bitwise AND this value with "and mask" and then bit shift the
337          * result "shift right" bits to the right.
338          * Assign "register" with appropriate configuration value.
339          */
340
341         CARD32 reg = *((CARD32 *) (&bios->data[offset + 1]));
342         CARD32 and = *((CARD32 *) (&bios->data[offset + 5]));
343         CARD8 shiftr = *((CARD8 *) (&bios->data[offset + 9]));
344         CARD8 nr = *((CARD8 *) (&bios->data[offset + 10]));
345         CARD32 reg2 = *((CARD32 *) (&bios->data[offset + 11]));
346         CARD8 configuration;
347         CARD32 configval, tmp;
348
349         if (iexec->execute) {
350                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: REG: 0x%04X\n", offset, 
351                                 reg);
352
353                 nv32_rd(pScrn, reg, &tmp);
354                 configuration = (tmp & and) >> shiftr;
355
356                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: CONFIGURATION TO USE: 0x%02X\n", 
357                                 offset, configuration);
358
359                 if (configuration <= nr) {
360
361                         configval = 
362                                 *((CARD32 *) (&bios->data[offset + 15 + configuration * 4]));
363
364                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: REG: 0x%08X, VALUE: 0x%08X\n", offset, 
365                                         reg2, configval);
366                         
367                         nv32_rd(pScrn, reg2, &tmp);
368                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: CURRENT VALUE IS: 0x%08X\n",
369                                 offset, tmp);
370                         nv32_wr(pScrn, reg2, configval);
371                 }
372         }
373         return TRUE;
374 }
375
376 static Bool init_io_restrict_prog(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
377 {
378         /* INIT_IO_RESTRICT_PROG   opcode: 0x32 ('2')
379          * 
380          * offset      (8  bit): opcode
381          * offset + 1  (16 bit): CRTC port
382          * offset + 3  (8  bit): CRTC index
383          * offset + 4  (8  bit): mask
384          * offset + 5  (8  bit): shift
385          * offset + 6  (8  bit): count
386          * offset + 7  (32 bit): register
387          * offset + 11 (32 bit): configuration 1
388          * ...
389          * 
390          * Starting at offset + 11 there are "count" 32 bit values.
391          * To find out which value to use read index "CRTC index" on "CRTC port",
392          * AND this value with "mask" and then bit shift right "shift" bits.
393          * Read the appropriate value using this index and write to "register"
394          */
395
396         uint16_t crtcport = *((uint16_t *)(&bios->data[offset + 1]));
397         uint8_t crtcindex = *((uint8_t *)(&bios->data[offset + 3]));
398         uint8_t mask = *((uint8_t *)(&bios->data[offset + 4]));
399         uint8_t shift = *((uint8_t *)(&bios->data[offset + 5]));
400         uint8_t count = *((uint8_t *)(&bios->data[offset + 6]));
401         uint32_t reg = *((uint32_t *)(&bios->data[offset + 7]));
402         uint8_t config;
403         uint32_t configval;
404
405         if (!iexec->execute)
406                 return TRUE;
407
408         if (DEBUGLEVEL >= 6)
409                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
410                            "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, Shift: 0x%02X, Count: 0x%02X, Reg: 0x%08X\n",
411                            offset, crtcport, crtcindex, mask, shift, count, reg);
412
413         /* FIXME how to choose head?? */
414         nv_port_rd(pScrn, crtcport, crtcindex, &config, 0);
415         config = (config & mask) >> shift;
416         if (config > count) {
417                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
418                            "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
419                            offset, config, count);
420                 return FALSE;
421         }
422
423         configval = *((uint32_t *)(&bios->data[offset + 11 + config * 4]));
424
425         if (DEBUGLEVEL >= 6)
426                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
427                            "0x%04X: Writing config %02X\n", offset, config);
428
429         nv32_wr(pScrn, reg, configval);
430
431         return TRUE;
432 }
433
434 static Bool init_repeat(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
435 {
436         CARD8 repeats = *((CARD8 *) (&bios->data[offset + 1]));
437         CARD8 i;
438
439         if (iexec->execute) {
440                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: REPEATING FOLLOWING SEGMENT %d TIMES.\n", 
441                                 offset, repeats);
442
443                 iexec->repeat = TRUE;
444
445                 for (i = 0; i < repeats - 1; i++)
446                         parse_init_table(pScrn, bios, offset + 2, iexec);
447
448                 iexec->repeat = FALSE;
449         }
450         return TRUE;
451 }
452
453 static Bool init_end_repeat(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
454 {
455         if (iexec->repeat)
456                 return FALSE;
457
458         return TRUE;
459 }
460
461 static Bool init_copy(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
462 {
463         /* INIT_COPY   opcode: 0x37 ('7')
464          *
465          * offset      (8  bit): opcode
466          * offset + 1  (32 bit): register
467          * offset + 5  (8  bit): shift
468          * offset + 6  (8  bit): srcmask
469          * offset + 7  (16 bit): CRTC port
470          * offset + 9  (8 bit): CRTC index
471          * offset + 10  (8 bit): mask
472          *
473          * Read index "CRTC index" on "CRTC port", AND with "mask", OR with
474          * (REGVAL("register") >> "shift" & "srcmask") and write-back to CRTC port
475          */
476
477         uint32_t reg = *((uint32_t *)(&bios->data[offset + 1]));
478         uint8_t shift = *((uint8_t *)(&bios->data[offset + 5]));
479         uint8_t srcmask = *((uint8_t *)(&bios->data[offset + 6]));
480         uint16_t crtcport = *((uint16_t *)(&bios->data[offset + 7]));
481         uint8_t crtcindex = *((uint8_t *)(&bios->data[offset + 9]));
482         uint8_t mask = *((uint8_t *)(&bios->data[offset + 10]));
483         uint32_t data;
484         uint8_t crtcdata;
485
486         if (!iexec->execute)
487                 return TRUE;
488
489         if (DEBUGLEVEL >= 6)
490                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
491                            "0x%04X: Reg: 0x%08X, Shift: 0x%02X, SrcMask: 0x%02X, Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X\n",
492                            offset, reg, shift, srcmask, crtcport, crtcindex, mask);
493
494         nv32_rd(pScrn, reg, &data);
495
496         if (shift < 0x80)
497                 data >>= shift;
498         else
499                 data <<= (0x100 - shift);
500
501         data &= srcmask;
502
503         /* FIXME how to choose head?? */
504         nv_port_rd(pScrn, crtcport, crtcindex, &crtcdata, 0);
505         crtcdata = (crtcdata & mask) | (uint8_t)data;
506         nv_port_wr(pScrn, crtcport, crtcindex, crtcdata, 0);
507
508         return TRUE;
509 }
510
511 static Bool init_not(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
512 {
513         /* INIT_NOT   opcode: 0x38 ('8')
514          *
515          * offset      (8  bit): opcode
516          *
517          * Invert the current execute / no-execute condition (i.e. "else")
518          */
519         if (iexec->execute)
520                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
521                            "0x%04X: ------ SKIPPING FOLLOWING COMMANDS  ------\n", offset);
522         else
523                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
524                            "0x%04X: ------ EXECUTING FOLLOWING COMMANDS ------\n", offset);
525
526         iexec->execute = !iexec->execute;
527         return TRUE;
528 }
529
530 static Bool io_flag_condition(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, uint8_t cond)
531 {
532         /* The IO flag condition entry has 2 bytes for the CRTC port; 1 byte
533          * for the CRTC index; 1 byte for the mask to apply to the value
534          * retrieved from the CRTC; 1 byte for the shift right to apply to the
535          * masked CRTC value; 2 bytes for the offset to the flag array, to
536          * which the shifted value is added; 1 byte for the mask applied to the
537          * value read from the flag array; and 1 byte for the value to compare
538          * against the masked byte from the flag table.
539          */
540
541         uint16_t condptr = bios->io_flag_condition_tbl_ptr + cond * IO_FLAG_CONDITION_SIZE;
542         uint16_t crtcport = *((uint16_t *)(&bios->data[condptr]));
543         uint8_t crtcindex = *((uint8_t *)(&bios->data[condptr + 2]));
544         uint8_t mask = *((uint8_t *)(&bios->data[condptr + 3]));
545         uint8_t shift = *((uint8_t *)(&bios->data[condptr + 4]));
546         uint16_t flagarray = *((uint16_t *)(&bios->data[condptr + 5]));
547         uint8_t flagarraymask = *((uint8_t *)(&bios->data[condptr + 7]));
548         uint8_t cmpval = *((uint8_t *)(&bios->data[condptr + 8]));
549         uint8_t data;
550
551         if (DEBUGLEVEL >= 6)
552                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
553                            "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, Shift: 0x%02X, FlagArray: 0x%04X, FAMask: 0x%02X, Cmpval: 0x%02X\n",
554                            offset, crtcport, crtcindex, mask, shift, flagarray, flagarraymask, cmpval);
555
556         /* FIXME how to choose head?? */
557         nv_port_rd(pScrn, crtcport, crtcindex, &data, 0);
558
559         data = *((uint8_t *)(&bios->data[flagarray + ((data & mask) >> shift)]));
560         data &= flagarraymask;
561
562         if (DEBUGLEVEL >= 6)
563                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
564                            "0x%04X: Checking if 0x%02X equals 0x%02X\n",
565                            offset, data, cmpval);
566
567         if (data == cmpval)
568                 return TRUE;
569
570         return FALSE;
571 }
572
573 static Bool init_io_flag_condition(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
574 {
575         /* INIT_IO_FLAG_CONDITION   opcode: 0x39 ('9')
576          *
577          * offset      (8 bit): opcode
578          * offset + 1  (8 bit): condition number
579          *
580          * Check condition "condition number" in the IO flag condition table.
581          * If condition not met skip subsequent opcodes until condition
582          * is inverted (INIT_NOT), or we hit INIT_RESUME
583          */
584
585         uint8_t cond = *((uint8_t *)(&bios->data[offset + 1]));
586
587         if (!iexec->execute)
588                 return TRUE;
589
590         if (io_flag_condition(pScrn, bios, offset, cond))
591                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
592                            "0x%04X: CONDITION FULFILLED - CONTINUING TO EXECUTE\n", offset);
593         else {
594                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
595                            "0x%04X: CONDITION IS NOT FULFILLED.\n", offset);
596                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
597                            "0x%04X: ------ SKIPPING FOLLOWING COMMANDS  ------\n", offset);
598                 iexec->execute = FALSE;
599         }
600
601         return TRUE;
602 }
603
604 static Bool init_io_restrict_pll(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
605 {
606         /* INIT_IO_RESTRICT_PLL   opcode: 0x34 ('4')
607          *
608          * offset      (8  bit): opcode
609          * offset + 1  (16 bit): CRTC port
610          * offset + 3  (8  bit): CRTC index
611          * offset + 4  (8  bit): mask
612          * offset + 5  (8  bit): shift
613          * offset + 6  (8  bit): IO flag condition index
614          * offset + 7  (8  bit): count
615          * offset + 8  (32 bit): register
616          * offset + 12 (16 bit): frequency 1
617          * ...
618          *
619          * Starting at offset + 12 there are "count" 16 bit frequencies (10kHz).
620          * Set PLL register "register" to coefficients for frequency n,
621          * selected by reading index "CRTC index" of "CRTC port" ANDed with
622          * "mask" and shifted right by "shift". If "IO flag condition index" > 0,
623          * and condition met, double frequency before setting it.
624          */
625
626         uint16_t crtcport = *((uint16_t *)(&bios->data[offset + 1]));
627         uint8_t crtcindex = *((uint8_t *)(&bios->data[offset + 3]));
628         uint8_t mask = *((uint8_t *)(&bios->data[offset + 4]));
629         uint8_t shift = *((uint8_t *)(&bios->data[offset + 5]));
630         int8_t io_flag_condition_idx = *((int8_t *)(&bios->data[offset + 6]));
631         uint8_t count = *((uint8_t *)(&bios->data[offset + 7]));
632         uint32_t reg = *((uint32_t *)(&bios->data[offset + 8]));
633         uint8_t config;
634         uint16_t freq;
635
636         if (!iexec->execute)
637                 return TRUE;
638
639         if (DEBUGLEVEL >= 6)
640                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
641                            "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, Shift: 0x%02X, IO Flag Condition: 0x%02X, Count: 0x%02X, Reg: 0x%08X\n",
642                            offset, crtcport, crtcindex, mask, shift, io_flag_condition_idx, count, reg);
643
644         /* FIXME how to choose head?? */
645         nv_port_rd(pScrn, crtcport, crtcindex, &config, 0);
646         config = (config & mask) >> shift;
647         if (config > count) {
648                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
649                            "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
650                            offset, config, count);
651                 return FALSE;
652         }
653
654         freq = *((uint16_t *)(&bios->data[offset + 12 + config * 2]));
655
656         if (io_flag_condition_idx > 0) {
657                 if (io_flag_condition(pScrn, bios, offset, io_flag_condition_idx)) {
658                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
659                                    "0x%04X: CONDITION FULFILLED - FREQ DOUBLED\n", offset);
660                         freq *= 2;
661                 } else
662                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
663                                    "0x%04X: CONDITION IS NOT FULFILLED. FREQ UNCHANGED\n", offset);
664         }
665
666         if (DEBUGLEVEL >= 6)
667                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
668                            "0x%04X: Reg: 0x%08X, Config: 0x%02X, Freq: %d0kHz\n",
669                            offset, reg, config, freq);
670
671         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
672
673 #if 0
674         switch (reg) {
675         case 0x00004004:
676                 configval = 0x01014E07;
677                 break;
678         case 0x00004024:
679                 configval = 0x13030E02;
680                 break;
681         }
682 #endif
683         return TRUE;
684 }
685
686 static Bool init_pll(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
687 {
688         /* INIT_PLL   opcode: 0x79 ('y')
689          *
690          * offset      (8  bit): opcode
691          * offset + 1  (32 bit): register
692          * offset + 5  (16 bit): freq
693          *
694          * Set PLL register "register" to coefficients for frequency (10kHz) "freq"
695          */
696
697         uint32_t reg = *((uint32_t *)(&bios->data[offset + 1]));
698         uint16_t freq = *((uint16_t *)(&bios->data[offset + 5]));
699
700         if (!iexec->execute)
701                 return TRUE;
702
703         if (DEBUGLEVEL >= 6)
704                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
705                            "0x%04X: Reg: 0x%04X, Freq: %d0kHz\n",
706                            offset, reg, freq);
707
708         /* FIXMElots */
709
710         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
711
712 #if 0
713         switch (reg) {
714                 case 0x00680508:
715                 configval = 0x00011F05;
716                 break;
717         }
718 #endif
719         return TRUE;
720 }
721
722 Bool init_idx_addr_latched(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
723 {
724         /* INIT_INDEX_ADDRESS_LATCHED   opcode: 0x49 ('I')
725          *
726          * offset      (8  bit): opcode
727          * offset + 1  (32 bit): register
728          * offset + 5  (32 bit): register
729          * offset + 9  (FIXME bit): FIXME
730          * offset + 17  (8 bit): count
731          * offset + 18 (8 bit): configuration 1
732          * offset + 19 (8 bit): configuration 1
733          * ...
734          *
735          * FIXME
736          */
737
738         uint32_t rega = *((uint32_t *)(&bios->data[offset + 1]));
739         uint32_t regb = *((uint32_t *)(&bios->data[offset + 5]));
740         uint8_t count = *((uint8_t *)(&bios->data[offset + 17]));
741         int i;
742
743         if (!iexec->execute)
744                 return TRUE;
745
746 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
747
748 #if 0
749         for (i = 0; i < count; i++) {
750                 nv_set_crtc_index(pScrn, crtcindex);
751
752                 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CRTC INDEX: %02X    DATA: %02X\n", offset,
753                                 crtcindex, initial_index + i);
754
755                 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%02X\n", offset,
756                                 nv_rd_crtc_data(pScrn));
757
758                 nv_wr_crtc_data(pScrn, initial_index + i);
759
760                 nv_set_crtc_index(pScrn, crtcdata);
761
762                 data = *((CARD8 *)(&bios->data[offset + 5 + i]));
763
764                 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CRTC INDEX: %02X    DATA: %02X\n", offset,
765                                 crtcdata, data);
766
767                 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%02X\n", offset,
768                                 nv_rd_crtc_data(pScrn));
769
770                 nv_wr_crtc_data(pScrn, data);
771         }
772 #endif
773         return TRUE;
774 }
775
776 Bool init_cr_idx_adr_latch(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
777 {
778         CARD8 crtcindex = *((CARD8 *) (&bios->data[offset + 1]));
779         CARD8 crtcdata = *((CARD8 *) (&bios->data[offset + 2]));
780         CARD8 initial_index = *((CARD8 *) (&bios->data[offset + 3]));
781         CARD8 entries = *((CARD8 *) (&bios->data[offset + 4]));
782         CARD8 data;
783         int i;
784
785         if (iexec->execute) {
786                 for (i = 0; i < entries; i++) {
787                         nv_set_crtc_index(pScrn, crtcindex);
788
789                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: CRTC INDEX: %02X    DATA: %02X\n", offset,
790                                         crtcindex, initial_index + i);
791
792                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: CURRENT VALUE IS: 0x%02X\n", offset, 
793                                         nv_rd_crtc_data(pScrn));
794
795                         nv_wr_crtc_data(pScrn, initial_index + i);
796
797                         nv_set_crtc_index(pScrn, crtcdata);
798
799                         data = *((CARD8 *) (&bios->data[offset + 5 + i]));
800
801                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: CRTC INDEX: %02X    DATA: %02X\n", offset,
802                                         crtcdata, data);
803
804                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: CURRENT VALUE IS: 0x%02X\n", offset, 
805                                         nv_rd_crtc_data(pScrn));
806
807                         nv_wr_crtc_data(pScrn, data);
808                 }
809         }
810         return TRUE;
811 }
812
813 Bool init_cr(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
814 {
815         /* XXX: IS THIS CORRECT? check the typecast .. probably wrong */
816
817         NVPtr pNv = NVPTR(pScrn);
818         CARD8 index = *((CARD32 *) (&bios->data[offset + 1])); 
819         CARD8 and = *((CARD8 *) (&bios->data[offset + 2]));
820         CARD8 or = *((CARD8 *) (&bios->data[offset + 3]));
821         CARD8 data;
822
823         if (iexec->execute) {
824                 nv_set_crtc_index(pScrn, index);
825                 data = (nv_rd_crtc_data(pScrn) & and) | or;
826                 /*printf("and: 0x%02x    or: 0x%02x\n", and, or);*/
827                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: CRTC INDEX: 0x%02X, VALUE: 0x%02X\n", offset, 
828                                 index, data);
829
830                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: CURRENT VALUE IS: 0x%02X\n", offset, 
831                                 nv_rd_crtc_data(pScrn));
832
833                 nv_wr_crtc_data(pScrn, data);
834         }
835         return TRUE;
836 }
837
838 static Bool init_zm_cr(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
839 {
840         /* INIT_ZM_CR   opcode: 0x53
841          * 
842          * offset      (8  bit): opcode
843          * offset + 1  (8  bit): CRTC index
844          * offset + 2  (8  bit): value
845          * 
846          * Assign "value" to CRTC register with index "CRTC index".
847          */
848
849         NVPtr pNv = NVPTR(pScrn);
850         CARD8 index = *((CARD32 *) (&bios->data[offset + 1]));
851         CARD8 value = *((CARD8 *) (&bios->data[offset + 2]));
852
853         if (iexec->execute) {
854                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: CRTC INDEX: 0x%02X, VALUE: 0x%02X\n", offset, 
855                                 index, value);
856
857                 nv_set_crtc_index(pScrn, index);
858
859                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: CURRENT VALUE IS: 0x%02X\n", offset, 
860                                 nv_rd_crtc_data(pScrn));
861
862                 nv_wr_crtc_data(pScrn, value);
863         }
864         return TRUE;
865 }
866
867 static Bool init_zm_cr_group(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
868 {
869         /* INIT_ZM_CR   opcode: 0x54
870          * 
871          * offset      (8  bit): opcode
872          * offset + 1  (8  bit): number of groups (index, value)
873          * offset + 2  (8  bit): index 1
874          * offset + 3  (8  bit): value 1
875          * ...
876          * 
877          * Assign "value n" to CRTC register with index "index n".
878          */
879     
880         CARD8 nr = *((CARD8 *) (&bios->data[offset + 1]));
881         CARD8 index, value;
882         int i;
883         
884         if (iexec->execute) {
885                 for (i = 0; i < nr; i++) {
886                         index = *((CARD8 *) (&bios->data[offset + 2 + 2 * i]));
887                         value = *((CARD8 *) (&bios->data[offset + 2 + 2 * i + 1]));
888
889                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: CRTC INDEX: 0x%02X, VALUE: 0x%02X\n", offset,
890                                         index, value);
891
892                         nv_set_crtc_index(pScrn, index);
893
894                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: CURRENT VALUE IS: 0x%02X\n", offset,
895                                         nv_rd_crtc_data(pScrn));
896                         nv_wr_crtc_data(pScrn, value);
897                 }
898         }
899         return TRUE;
900 }
901
902 static Bool init_condition_time(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
903 {
904         /* My BIOS does not use this command. */
905         xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
906
907         return FALSE;
908 }
909
910 static Bool init_zm_reg_sequence(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
911 {
912         /* INIT_ZM_REG_SEQUENCE   opcode: 0x58
913          * 
914          * offset      (8  bit): opcode
915          * offset + 1  (32 bit): register base
916          * offset + 5  (8  bit): nr
917          * offset + 6  (32 bit): value to assign "register base" + 4
918          * ...
919          * 
920          * Initialzies a sequence of "nr" registers starting at "register base".
921          */
922
923         CARD32 reg = *((CARD32 *) (&bios->data[offset + 1]));
924         CARD32 nr = *((CARD8 *) (&bios->data[offset + 5]));
925         CARD32 data;
926         CARD32 tmp;
927         int i;
928
929         if (iexec->execute) {
930                 for (i = 0; i < nr; i++) {
931                         data = *((CARD32 *) (&bios->data[offset + 6 + i * 4]));
932                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: REG: 0x%08X, VALUE: 0x%08X\n", offset,
933                                         reg + i * 4, data);
934
935                         nv32_rd(pScrn, reg + i * 4, &tmp);
936                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: CURRENT VALUE IS: 0x%08X\n",
937                                 offset, tmp);
938
939                         nv32_wr(pScrn, reg + i * 4, data);
940                 }
941         }
942         return TRUE;
943 }
944
945 static Bool init_indirect_reg(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
946 {
947         /* INIT_INDIRECT_REG opcode: 0x5A
948          * 
949          * offset      (8  bit): opcode
950          * offset + 1  (32 bit): register
951          * offset + 5  (16 bit): adress offset (in bios)
952          *
953          * Lookup value at offset data in the bios and write it to reg
954          */
955         NVPtr pNv = NVPTR(pScrn);
956         CARD32 reg = *((CARD32 *) (&bios->data[offset + 1]));
957         CARD32 data = *((CARD16 *) (&bios->data[offset + 5]));
958         CARD32 data2 = bios->data[data];
959
960         if (iexec->execute) {
961                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,  
962                                 "0x%04X: REG: 0x%04X, DATA AT: 0x%04X, VALUE IS: 0x%08X\n", 
963                                 offset, reg, data, data2);
964
965                 if (DEBUGLEVEL >= 6) {
966                         CARD32 tmpval;
967                         nv32_rd(pScrn, reg, &tmpval);
968                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: CURRENT VALUE IS: 0x%08X\n", offset, tmpval);
969                 }
970
971                 nv32_wr(pScrn, reg, data2);
972         }
973         return TRUE;
974 }
975
976 static Bool init_sub_direct(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
977 {
978         /* INIT_SUB_DIRECT   opcode: 0x5B
979          * 
980          * offset      (8  bit): opcode
981          * offset + 1  (16 bit): subroutine offset (in bios)
982          *
983          * Calls a subroutine that will execute commands until INIT_DONE
984          * is found. 
985          */
986
987         CARD16 sub_offset = *((CARD16 *) (&bios->data[offset + 1]));
988
989         if (iexec->execute) {
990                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: EXECUTING SUB-ROUTINE AT: 0x%04X\n", 
991                                 offset, sub_offset);
992
993                 parse_init_table(pScrn, bios, sub_offset, iexec);
994
995                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: END OF SUB-ROUTINE\n", offset);
996         }
997         return TRUE;
998 }
999
1000 static Bool init_copy_nv_reg(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1001 {   
1002         CARD32 srcreg = *((CARD32 *) (&bios->data[offset + 1]));
1003         CARD8 shift = *((CARD8 *) (&bios->data[offset + 5]));
1004         CARD32 and1 = *((CARD32 *) (&bios->data[offset + 6]));
1005         CARD32 xor = *((CARD32 *) (&bios->data[offset + 10]));
1006         CARD32 dstreg = *((CARD32 *) (&bios->data[offset + 14]));
1007         CARD32 and2 = *((CARD32 *) (&bios->data[offset + 18]));
1008         CARD32 srcdata;
1009         CARD32 dstdata;
1010         
1011         if (iexec->execute) {
1012                 nv32_rd(pScrn, srcreg, &srcdata);
1013                 
1014                 if (shift > 0)
1015                         srcdata >>= shift;
1016                 else
1017                         srcdata <<= shift;
1018
1019                 srcdata = (srcdata & and1) ^ xor;
1020
1021                 nv32_rd(pScrn, dstreg, &dstdata);
1022                 dstdata &= and2;
1023
1024                 dstdata |= srcdata;
1025
1026                 CARD32 tmp;             
1027                 nv32_rd(pScrn, dstreg, &tmp);
1028
1029                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: REG: 0x%08X, VALUE: 0x%08X\n", offset, dstreg, 
1030                                 dstdata);
1031
1032                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: CURRENT VALUE IS: 0x%08X\n", offset, tmp);
1033
1034                 nv32_wr(pScrn, dstreg, dstdata);
1035         }
1036         return TRUE;
1037 }
1038
1039 static Bool init_zm_index_io(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1040 {
1041         /* INIT_ZM_INDEX_IO   opcode: 0x62 ('b')
1042          *
1043          * offset      (8  bit): opcode
1044          * offset + 1  (16 bit): CRTC port
1045          * offset + 3  (8  bit): CRTC index
1046          * offset + 4  (8  bit): data
1047          *
1048          * Write "data" to index "CRTC index" of "CRTC port"
1049          */
1050         uint16_t crtcport = *((uint16_t *)(&bios->data[offset + 1]));
1051         uint8_t crtcindex = *((uint8_t *)(&bios->data[offset + 3]));
1052         uint8_t data = *((uint8_t *)(&bios->data[offset + 4]));
1053
1054         if (!iexec->execute)
1055                 return TRUE;
1056
1057         /* FIXME how to choose head?? */
1058         nv_port_wr(pScrn, crtcport, crtcindex, data, 0);
1059
1060         return TRUE;
1061 }
1062
1063 static Bool init_compute_mem(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1064 {
1065         /* INIT_COMPUTE_MEM   opcode: 0x63 ('c')
1066          *
1067          * offset      (8 bit): opcode
1068          *
1069          * FIXME
1070          */
1071
1072         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
1073 #if 0
1074         uint16_t ramcfg = *((uint16_t *)(&bios->data[bios->ram_table_offset]));
1075         uint32_t pfb_debug;
1076         uint32_t strapinfo;
1077         uint32_t ramcfg2;
1078
1079         if (!iexec->execute)
1080                 return TRUE;
1081
1082         nv32_rd(pScrn, 0x00101000, &strapinfo);
1083         nv32_rd(pScrn, 0x00100080, &pfb_debug);
1084
1085         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "STRAPINFO: 0x%08X\n", strapinfo);
1086         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PFB_DEBUG: 0x%08X\n", pfb_debug);
1087         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RAM CFG: 0x%04X\n", ramcfg);
1088
1089         pfb_debug &= 0xffffffef;
1090         strapinfo >>= 2;
1091         strapinfo &= 0x0000000f;
1092         ramcfg2 = *((uint16_t *)
1093                         (&bios->data[bios->ram_table_offset + (2 * strapinfo)]));
1094
1095         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "AFTER MANIPULATION\n");
1096         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "STRAPINFO: 0x%08X\n", strapinfo);
1097         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PFB_DEBUG: 0x%08X\n", pfb_debug);
1098         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RAM CFG2: 0x%08X\n", ramcfg2);
1099
1100
1101         uint32_t reg1;
1102         uint32_t reg2;
1103
1104         nv32_rd(pScrn, 0x00100200, &reg1);
1105         nv32_rd(pScrn, 0x0010020C, &reg2);
1106
1107         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x00100200: 0x%08X\n", reg1);
1108         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x0010020C: 0x%08X\n", reg2);
1109 #endif
1110
1111         return TRUE;
1112 }
1113
1114 #define NV_PBUS_PCI_NV_19       0x0000184C
1115
1116 static Bool init_reset(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1117 {
1118         /* INIT_RESET   opcode: 0x65 ('e')
1119          *
1120          * offset      (8  bit): opcode
1121          * offset + 1  (32 bit): register
1122          * offset + 5  (32 bit): value1
1123          * offset + 9  (32 bit): value2
1124          *
1125          * Assign "value1" to "register", then assign "value2" to "register"
1126          */
1127
1128         uint32_t reg = *((uint32_t *)(&bios->data[offset + 1]));
1129         uint32_t value1 = *((uint32_t *)(&bios->data[offset + 5]));
1130         uint32_t value2 = *((uint32_t *)(&bios->data[offset + 9]));
1131         uint32_t pci_nv_19;
1132
1133         if (!iexec->execute)
1134                 return TRUE;
1135
1136         if (DEBUGLEVEL >= 6)
1137                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1138                            "0x%04X: Reg: 0x%08X, Value1: 0x%08X, Value2: 0x%08X\n",
1139                            offset, reg, value1, value2);
1140
1141         /* it's not clear from my .dmp file, but it seems we should zero out NV_PBUS_PCI_NV_19(0x0000184C) and then restore it */
1142         nv32_rd(pScrn, NV_PBUS_PCI_NV_19, &pci_nv_19);
1143 #if 0
1144         nv32_rd(pScrn, PCICFG(PCICFG_ROMSHADOW), &tmpval);
1145         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: PCICFG_ROMSHADOW: 0x%02X\n", offset, tmpval);
1146 #endif
1147         nv32_wr(pScrn, NV_PBUS_PCI_NV_19, 0);
1148         nv32_wr(pScrn, reg, value1);
1149         nv32_wr(pScrn, reg, value2);
1150         nv32_wr(pScrn, NV_PBUS_PCI_NV_19, pci_nv_19);
1151
1152         /* PCI Config space init needs to be added here. */
1153         /* if (nv32_rd(pScrn, PCICFG(PCICFG_ROMSHADOW), value1)) */
1154         /*     nv32_wr(pScrn, PCICFG(PCICFG_ROMSHADOW), value1 & 0xfffffffe) */
1155
1156         return TRUE;
1157 }
1158
1159 static Bool init_index_io8(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1160 {
1161         /* INIT_INDEX_IO8   opcode: 0x69
1162          * 
1163          * offset      (8  bit): opcode
1164          * offset + 1  (16 bit): CRTC reg
1165          * offset + 3  (8  bit): and mask
1166          * offset + 4  (8  bit): or with
1167          * 
1168          * 
1169          */
1170
1171         NVPtr pNv = NVPTR(pScrn);
1172         /* FIXME how to choose head?? */
1173         volatile CARD8 *ptr = pNv->cur_head ? pNv->PCIO1 : pNv->PCIO0;
1174         CARD16 reg = *((CARD16 *)(&bios->data[offset + 1]));
1175         CARD8 and  = *((CARD8 *)(&bios->data[offset + 3]));
1176         CARD8 or = *((CARD8 *)(&bios->data[offset + 4]));
1177         CARD8 data;
1178
1179         if (iexec->execute) {
1180                 data = (VGA_RD08(ptr, reg) & and) | or;
1181
1182                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,  
1183                                 "0x%04X: CRTC REG: 0x%04X, VALUE: 0x%02X\n", 
1184                                 offset, reg, data);
1185                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: CURRENT VALUE IS: 0x%02X\n", offset, 
1186                                 VGA_RD08(ptr, reg));
1187
1188 #ifdef PERFORM_WRITE
1189                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "init_index_io8 crtcreg 0x%X value 0x%X\n",reg,data);
1190                 still_alive();
1191                 VGA_WR08(ptr, reg, data);
1192 #endif
1193         }
1194         return TRUE;
1195 }
1196
1197 static Bool init_sub(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1198 {
1199         CARD8 sub = *((CARD8 *) (&bios->data[offset + 1]));
1200
1201         if (iexec->execute) {
1202                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: EXECUTING SUB-SCRIPT: %d\n", offset, sub);
1203
1204                 parse_init_table(pScrn, bios, 
1205                                 *((CARD16 *) (&bios->data[bios->init_script_tbls_ptr + sub * 2])),
1206                                 iexec);
1207
1208                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: END OF SUB-SCRIPT\n", offset);
1209         }
1210         return TRUE;
1211 }
1212
1213 static Bool init_ram_condition(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1214 {
1215         /* INIT_RAM_CONDITION   opcode: 0x6D
1216          * 
1217          * offset      (8  bit): opcode
1218          * offset + 1  (8  bit): and mask
1219          * offset + 2  (8  bit): cmpval
1220          *
1221          * Test if (NV_PFB_BOOT & and mask) matches cmpval
1222          */
1223         NVPtr pNv = NVPTR(pScrn);
1224         CARD8 and = *((CARD8 *) (&bios->data[offset + 1]));
1225         CARD8 cmpval = *((CARD8 *) (&bios->data[offset + 2]));
1226         CARD32 data;
1227
1228         if (iexec->execute) {
1229                 data=(pNv->PFB[NV_PFB_BOOT/4])&and;
1230
1231                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,  
1232                                 "0x%04X: CHECKING IF REGVAL: 0x%08X equals COND: 0x%08X\n",
1233                                 offset, data, cmpval);
1234
1235                 if (data == cmpval) {
1236                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,  
1237                                         "0x%04X: CONDITION FULFILLED - CONTINUING TO EXECUTE\n",
1238                                         offset);
1239                 } else {
1240                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: CONDITION IS NOT FULFILLED.\n", offset);
1241                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,  
1242                                         "0x%04X: ------ SKIPPING FOLLOWING COMMANDS  ------\n", offset);
1243                         iexec->execute = FALSE;     
1244                 }
1245         }
1246         return TRUE;
1247 }
1248
1249 static Bool init_nv_reg(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1250 {
1251         /* INIT_NV_REG   opcode: 0x6E ('n')
1252          * 
1253          * offset      (8  bit): opcode
1254          * offset + 1  (32 bit): register
1255          * offset + 5  (32 bit): mask
1256          * offset + 9  (32 bit): data
1257          *
1258          * Assign ((REGVAL("register") & "mask") | "data") to "register"
1259          */
1260
1261         uint32_t reg = *((uint32_t *)(&bios->data[offset + 1]));
1262         uint32_t mask = *((uint32_t *)(&bios->data[offset + 5]));
1263         uint32_t data = *((uint32_t *)(&bios->data[offset + 9]));
1264         uint32_t value;
1265
1266         if (!iexec->execute)
1267                 return TRUE;
1268
1269         if (DEBUGLEVEL >= 6)
1270                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1271                            "0x%04X: Reg: 0x%08X, Mask: 0x%08X, Data: 0x%08X\n",
1272                            offset, reg, mask, data);
1273
1274         nv32_rd(pScrn, reg, &value);
1275
1276         value = (value & mask) | data;
1277
1278         nv32_wr(pScrn, reg, value);
1279
1280         return TRUE;
1281 }
1282
1283 static Bool init_macro(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1284 {
1285         /* INIT_MACRO   opcode: 0x6F ('o')
1286          *
1287          * offset      (8 bit): opcode
1288          * offset + 1  (8 bit): macro number
1289          *
1290          * Look up macro index "macro number" in the macro index table.
1291          * The macro index table entry has 1 byte for the index in the macro table,
1292          * and 1 byte for the number of times to repeat the macro.
1293          * The macro table entry has 4 bytes for the register address and
1294          * 4 bytes for the value to write to that register
1295          */
1296
1297         uint8_t macro_index_tbl_idx = *((uint8_t *)(&bios->data[offset + 1]));
1298         uint16_t tmp = bios->macro_index_tbl_ptr + (macro_index_tbl_idx * MACRO_INDEX_SIZE);
1299         uint8_t macro_tbl_idx = *((uint8_t *)(&bios->data[tmp]));
1300         uint8_t count = *((uint8_t *)(&bios->data[tmp + 1]));
1301         uint32_t reg, data;
1302         int i;
1303
1304         if (!iexec->execute)
1305                 return TRUE;
1306
1307         if (DEBUGLEVEL >= 6)
1308                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1309                            "0x%04X: Macro: 0x%02X, MacroTableIndex: 0x%02X, Count: 0x%02X\n",
1310                            offset, macro_index_tbl_idx, macro_tbl_idx, count);
1311
1312         for (i = 0; i < count; i++) {
1313                 reg = *((uint32_t *)
1314                         (&bios->data[bios->macro_tbl_ptr + (macro_tbl_idx + i) * MACRO_SIZE]));
1315                 data = *((uint32_t *)
1316                         (&bios->data[bios->macro_tbl_ptr + (macro_tbl_idx + i) * MACRO_SIZE + 4]));
1317
1318                 nv32_wr(pScrn, reg, data);
1319         }
1320
1321         return TRUE;
1322 }
1323
1324 static Bool init_done(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1325 {
1326         /* INIT_DONE   opcode: 0x71 ('q')
1327          *
1328          * offset      (8  bit): opcode
1329          *
1330          * End the current script
1331          */
1332
1333         /* mild retval abuse to stop parsing this table */
1334         return FALSE;
1335 }
1336
1337 static Bool init_resume(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1338 {
1339         /* INIT_RESUME   opcode: 0x72 ('r')
1340          *
1341          * offset      (8  bit): opcode
1342          *
1343          * End the current execute / no-execute condition
1344          */
1345
1346         if (iexec->execute)
1347                 return TRUE;
1348
1349         iexec->execute = TRUE;;
1350         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1351                    "0x%04X: ---- EXECUTING FOLLOWING COMMANDS ----\n", offset);
1352
1353         return TRUE;
1354 }
1355
1356 static Bool init_ram_condition2(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1357 {
1358         /* INIT_RAM_CONDITION2   opcode: 0x73
1359          * 
1360          * offset      (8  bit): opcode
1361          * offset + 1  (8  bit): and mask
1362          * offset + 2  (8  bit): cmpval
1363          *
1364          * Test if (NV_EXTDEV_BOOT & and mask) matches cmpval
1365          */
1366         NVPtr pNv = NVPTR(pScrn);
1367         CARD32 and = *((CARD32 *) (&bios->data[offset + 1]));
1368         CARD32 cmpval = *((CARD32 *) (&bios->data[offset + 5]));
1369         CARD32 data;
1370
1371         if (iexec->execute) {
1372                 data=(nvReadEXTDEV(pNv, NV_PEXTDEV_BOOT))&and;
1373                 
1374                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,  
1375                                 "0x%04X: CHECKING IF REGVAL: 0x%08X equals COND: 0x%08X\n",
1376                                 offset, data, cmpval);
1377
1378                 if (data == cmpval) {
1379                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,  
1380                                         "0x%04X: CONDITION FULFILLED - CONTINUING TO EXECUTE\n",
1381                                         offset);
1382                 } else {
1383                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,  "0x%04X: CONDITION IS NOT FULFILLED.\n", offset);
1384                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,  
1385                                         "0x%04X: ------ SKIPPING FOLLOWING COMMANDS  ------\n", offset);
1386                         iexec->execute = FALSE;     
1387                 }
1388         }
1389         return TRUE;
1390 }
1391
1392 static Bool init_time(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1393 {
1394         /* INIT_TIME   opcode: 0x74 ('t')
1395          * 
1396          * offset      (8  bit): opcode
1397          * offset + 1  (16 bit): time
1398          * 
1399          * Sleep for "time" microseconds.
1400          */
1401
1402         uint16_t time = *((uint16_t *)(&bios->data[offset + 1]));
1403
1404         if (!iexec->execute)
1405                 return TRUE;
1406
1407         if (DEBUGLEVEL >= 6)
1408                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1409                            "0x%04X: Sleeping for 0x%04X microseconds.\n", offset, time);
1410
1411         usleep(time);
1412
1413         return TRUE;
1414 }
1415
1416 static Bool init_condition(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1417 {
1418         /* INIT_CONDITION   opcode: 0x75 ('u')
1419          *
1420          * offset      (8 bit): opcode
1421          * offset + 1  (8 bit): condition number
1422          *
1423          * Check condition "condition number" in the condition table.
1424          * The condition table entry has 4 bytes for the address of the
1425          * register to check, 4 bytes for a mask and 4 for a test value.
1426          * If condition not met skip subsequent opcodes until condition
1427          * is inverted (INIT_NOT), or we hit INIT_RESUME
1428          */
1429
1430         uint8_t cond = *((uint8_t *)(&bios->data[offset + 1]));
1431         uint16_t condptr = bios->condition_tbl_ptr + cond * CONDITION_SIZE;
1432         uint32_t reg = *((uint32_t *)
1433                         (&bios->data[condptr]));
1434         uint32_t mask = *((uint32_t *)
1435                         (&bios->data[condptr + 4]));
1436         uint32_t cmpval = *((uint32_t *)
1437                         (&bios->data[condptr + 8]));
1438         uint32_t data;
1439
1440         if (!iexec->execute)
1441                 return TRUE;
1442
1443         if (DEBUGLEVEL >= 6)
1444                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1445                            "0x%04X: Cond: 0x%02X, Reg: 0x%08X, Mask: 0x%08X, Cmpval: 0x%08X\n",
1446                            offset, cond, reg, mask, cmpval);
1447
1448         nv32_rd(pScrn, reg, &data);
1449         data &= mask;
1450
1451         if (DEBUGLEVEL >= 6)
1452                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1453                            "0x%04X: Checking if 0x%08X equals 0x%08X\n",
1454                            offset, data, cmpval);
1455
1456         if (data == cmpval) {
1457                 if (DEBUGLEVEL >= 6)
1458                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1459                                    "0x%04X: CONDITION FULFILLED - CONTINUING TO EXECUTE\n", offset);
1460         } else {
1461                 if (DEBUGLEVEL >= 6)
1462                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1463                                    "0x%04X: CONDITION IS NOT FULFILLED.\n", offset);
1464                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1465                            "0x%04X: ------ SKIPPING FOLLOWING COMMANDS  ------\n", offset);
1466                 iexec->execute = FALSE;
1467         }
1468
1469         return TRUE;
1470 }
1471
1472 static Bool init_index_io(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1473 {
1474         /* INIT_INDEX_IO   opcode: 0x78 ('x')
1475          * 
1476          * offset      (8  bit): opcode
1477          * offset + 1  (16 bit): CRTC port
1478          * offset + 3  (8  bit): CRTC index
1479          * offset + 4  (8  bit): mask
1480          * offset + 5  (8  bit): data
1481          * 
1482          * Read value at index "CRTC index" on "CRTC port", AND with "mask", OR with "data", write-back
1483          */
1484
1485         uint16_t crtcport = *((uint16_t *)(&bios->data[offset + 1]));
1486         uint8_t crtcindex = *((uint8_t *)(&bios->data[offset + 3]));
1487         uint8_t mask = *((uint8_t *)(&bios->data[offset + 4]));
1488         uint8_t data = *((uint8_t *)(&bios->data[offset + 5]));
1489         uint8_t value;
1490         
1491         if (!iexec->execute)
1492                 return TRUE;
1493
1494         if (DEBUGLEVEL >= 6)
1495                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1496                            "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%08X, Data: 0x%08X\n",
1497                            offset, crtcport, crtcindex, mask, data);
1498
1499         /* FIXME how to choose head?? */
1500         nv_port_rd(pScrn, crtcport, crtcindex, &value, 0);
1501         value = (value & mask) | data;
1502         nv_port_wr(pScrn, crtcport, crtcindex, value, 0);
1503
1504         return TRUE;
1505 }
1506
1507 static Bool init_zm_reg(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1508 {
1509         /* INIT_ZM_REG   opcode: 0x7A ('z')
1510          * 
1511          * offset      (8  bit): opcode
1512          * offset + 1  (32 bit): register
1513          * offset + 5  (32 bit): value
1514          * 
1515          * Assign "value" to "register"
1516          */
1517
1518         uint32_t reg = *((uint32_t *)(&bios->data[offset + 1]));
1519         uint32_t value = *((uint32_t *)(&bios->data[offset + 5]));
1520
1521         if (!iexec->execute)
1522                 return TRUE;
1523
1524         nv32_wr(pScrn, reg, value);
1525
1526         return TRUE;
1527 }
1528
1529 static init_tbl_entry_t itbl_entry[] = {
1530         /* command name                       , id  , length  , offset  , mult    , command handler                 */
1531         { "INIT_PROG"                         , 0x31, 15      , 10      , 4       , init_prog                       },
1532         { "INIT_IO_RESTRICT_PROG"             , 0x32, 11      , 6       , 4       , init_io_restrict_prog           },
1533         { "INIT_REPEAT"                       , 0x33, 2       , 0       , 0       , init_repeat                     },
1534         { "INIT_IO_RESTRICT_PLL"              , 0x34, 12      , 7       , 2       , init_io_restrict_pll            },
1535         { "INIT_END_REPEAT"                   , 0x36, 1       , 0       , 0       , init_end_repeat                 },
1536         { "INIT_COPY"                         , 0x37, 11      , 0       , 0       , init_copy                       },
1537         { "INIT_NOT"                          , 0x38, 1       , 0       , 0       , init_not                        },
1538         { "INIT_IO_FLAG_CONDITION"            , 0x39, 2       , 0       , 0       , init_io_flag_condition          },
1539         { "INIT_INDEX_ADDRESS_LATCHED"        , 0x49, 18      , 17      , 2       , init_idx_addr_latched           },
1540 /*      { "INIT_IO_RESTRICT_PLL"              , 0x4A, 43      , 0       , 0       , init_io_restrict_pll            }, */
1541 /*      { "INIT_PLL"                          , 0x4B, 9       , 0       , 0       , init_pll                        }, */
1542 /*      { "INIT_I2C_BYTE"                     , 0x4C, x       , x       , x       , init_i2c_byte                   }, */
1543 /*      { "INIT_ZM_I2C_BYTE"                  , 0x4D, x       , x       , x       , init_zm_i2c_byte                }, */
1544 /*      { "INIT_ZM_I2C"                       , 0x4E, x       , x       , x       , init_zm_i2c                     }, */
1545         { "INIT_CR_INDEX_ADDRESS_LATCHED"     , 0x51, 5       , 4       , 1       , init_cr_idx_adr_latch           },
1546         { "INIT_CR"                           , 0x52, 4       , 0       , 0       , init_cr                         },
1547         { "INIT_ZM_CR"                        , 0x53, 3       , 0       , 0       , init_zm_cr                      },
1548         { "INIT_ZM_CR_GROUP"                  , 0x54, 2       , 1       , 2       , init_zm_cr_group                },
1549         { "INIT_CONDITION_TIME"               , 0x56, 3       , 0       , 0       , init_condition_time             },
1550         { "INIT_ZM_REG_SEQUENCE"              , 0x58, 6       , 5       , 4       , init_zm_reg_sequence            },
1551         { "INIT_INDIRECT_REG"                 , 0x5A, 7       , 0       , 0       , init_indirect_reg               },
1552         { "INIT_SUB_DIRECT"                   , 0x5B, 3       , 0       , 0       , init_sub_direct                 },
1553         { "INIT_COPY_NV_REG"                  , 0x5F, 22      , 0       , 0       , init_copy_nv_reg                },
1554         { "INIT_ZM_INDEX_IO"                  , 0x62, 5       , 0       , 0       , init_zm_index_io                },
1555         { "INIT_COMPUTE_MEM"                  , 0x63, 1       , 0       , 0       , init_compute_mem                },
1556         { "INIT_RESET"                        , 0x65, 13      , 0       , 0       , init_reset                      },
1557 /*      { "INIT_NEXT"                         , 0x66, x       , x       , x       , init_next                       }, */       
1558 /*      { "INIT_NEXT"                         , 0x67, x       , x       , x       , init_next                       }, */       
1559 /*      { "INIT_NEXT"                         , 0x68, x       , x       , x       , init_next                       }, */       
1560         { "INIT_INDEX_IO8"                    , 0x69, 5       , 0       , 0       , init_index_io8                  },
1561         { "INIT_SUB"                          , 0x6B, 2       , 0       , 0       , init_sub                        },
1562         { "INIT_RAM_CONDITION"                , 0x6D, 3       , 0       , 0       , init_ram_condition              },
1563         { "INIT_NV_REG"                       , 0x6E, 13      , 0       , 0       , init_nv_reg                     },
1564         { "INIT_MACRO"                        , 0x6F, 2       , 0       , 0       , init_macro                      },
1565         { "INIT_DONE"                         , 0x71, 1       , 0       , 0       , init_done                       },
1566         { "INIT_RESUME"                       , 0x72, 1       , 0       , 0       , init_resume                     },
1567         { "INIT_RAM_CONDITION2"               , 0x73, 9       , 0       , 0       , init_ram_condition2             },
1568         { "INIT_TIME"                         , 0x74, 3       , 0       , 0       , init_time                       },
1569         { "INIT_CONDITION"                    , 0x75, 2       , 0       , 0       , init_condition                  },
1570 /*      { "INIT_IO_CONDITION"                 , 0x76, x       , x       , x       , init_io_condition               }, */
1571         { "INIT_INDEX_IO"                     , 0x78, 6       , 0       , 0       , init_index_io                   },
1572         { "INIT_PLL"                          , 0x79, 7       , 0       , 0       , init_pll                        },
1573         { "INIT_ZM_REG"                       , 0x7A, 9       , 0       , 0       , init_zm_reg                     },
1574 /*      { "INIT_RAM_RESTRICT_ZM_REG_GROUP"    , 0x8F, x       , x       , x       , init_ram_restrict_zm_reg_group  }, */
1575 /*      { "INIT_COPY_ZM_REG"                  , 0x90, x       , x       , x       , init_copy_zm_reg                }, */
1576 /*      { "INIT_ZM_REG_GROUP_ADDRESS_LATCHED" , 0x91, x       , x       , x       , init_zm_reg_group_addr_latched  }, */
1577 /*      { "INIT_RESERVED"                     , 0x92, x       , x       , x       , init_reserved                   }, */
1578         { 0                                   , 0   , 0       , 0       , 0       , 0                               }
1579 };
1580
1581 static unsigned int get_init_table_entry_length(bios_t *bios, unsigned int offset, int i)
1582 {
1583         /* Calculates the length of a given init table entry. */
1584         return itbl_entry[i].length + bios->data[offset + itbl_entry[i].length_offset]*itbl_entry[i].length_multiplier;
1585 }
1586
1587 static void parse_init_table(ScrnInfoPtr pScrn, bios_t *bios, unsigned int offset, init_exec_t *iexec)
1588 {
1589         /* Parses all commands in a init table. */
1590
1591         /* We start out executing all commands found in the
1592          * init table. Some op codes may change the status
1593          * of this variable to SKIP, which will cause
1594          * the following op codes to perform no operation until
1595          * the value is changed back to EXECUTE.
1596          */
1597         unsigned char id;
1598         int i;
1599
1600         int count=0;
1601         /* Loop until INIT_DONE causes us to break out of the loop
1602          * (or until offset > bios length just in case... )
1603          * (and no more than 10000 iterations just in case... ) */
1604         while ((offset < bios->length) && (count++ < 10000)) {
1605                 id = bios->data[offset];
1606
1607                 /* Find matching id in itbl_entry */
1608                 for (i = 0; itbl_entry[i].name && (itbl_entry[i].id != id); i++)
1609                         ;
1610
1611                 if (itbl_entry[i].name) {
1612                         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ (0x%02X) - %s ]\n",
1613                                    offset, itbl_entry[i].id, itbl_entry[i].name);
1614
1615                         /* execute eventual command handler */
1616                         if (itbl_entry[i].handler)
1617                                 if (!(*itbl_entry[i].handler)(pScrn, bios, offset, iexec))
1618                                         break;
1619                 } else {
1620                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1621                                    "0x%04X: Init table command not found: 0x%02X\n", offset, id);
1622                         break;
1623                 }
1624
1625                 /* Add the offset of the current command including all data
1626                  * of that command. The offset will then be pointing on the
1627                  * next op code.
1628                  */
1629                 offset += get_init_table_entry_length(bios, offset, i);
1630         }
1631 }
1632
1633 void parse_init_tables(ScrnInfoPtr pScrn, bios_t *bios)
1634 {
1635         /* Loops and calls parse_init_table() for each present table. */
1636
1637         int i = 0;
1638         uint16_t table;
1639         init_exec_t iexec = {TRUE, FALSE};
1640
1641         while ((table = *((uint16_t *)(&bios->data[bios->init_script_tbls_ptr + i])))) {
1642
1643                 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: Parsing init table %d\n",
1644                         table, i / 2);
1645
1646                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1647                            "0x%04X: ------ EXECUTING FOLLOWING COMMANDS ------\n", table);
1648                 still_alive();
1649                 parse_init_table(pScrn, bios, table, &iexec);
1650                 i += 2;
1651         }
1652 }
1653
1654 static void parse_fp_tables(ScrnInfoPtr pScrn, bios_t *bios)
1655 {
1656         NVPtr pNv = NVPTR(pScrn);
1657         unsigned int fpstrapping;
1658         uint8_t *fptable, *fpxlatetable;
1659 /*      uint8_t *lvdsmanufacturertable, *fpxlatemanufacturertable;*/
1660         unsigned int fpindex;/* lvdsmanufacturerindex;*/
1661         uint8_t fptable_ver, headerlen = 0, recordlen = 44;
1662         int ofs;
1663         DisplayModePtr mode;
1664
1665         fpstrapping = (nvReadEXTDEV(pNv, NV_PEXTDEV_BOOT) >> 16) & 0xf;
1666
1667         if (bios->fptablepointer == 0x0) {
1668                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1669                            "Pointer to flat panel table invalid\n");
1670                 return;
1671         }
1672
1673         fptable = &bios->data[bios->fptablepointer];
1674
1675         fptable_ver = fptable[0];
1676
1677         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1678                    "Found flat panel mode table revision %d.%d\n",
1679                    fptable_ver >> 4, fptable_ver & 0xf);
1680
1681         switch (fptable_ver) {
1682         /* PINS version 0x5.0x11 BIOSen have version 1 like tables, but no version field,
1683          * and miss one of the spread spectrum/PWM bytes.
1684          * This could affect early GF2Go parts (not seen any appropriate ROMs though).
1685          * Here we assume that a version of 0x00 matches this case (combining with a
1686          * PINS version check would be better), as the common case for the panel type
1687          * field is 0x0005, and that is in fact what we are reading the first byte of. */
1688         case 0x00:      /* some NV11, 15, 16 */
1689                 /* note that in this version the lvdsmanufacturertable is not defined */
1690                 ofs = 6;
1691                 recordlen = 42;
1692                 goto v1common;
1693         case 0x10:      /* some NV15/16, and NV11+ */
1694                 ofs = 7;
1695 v1common:
1696                 if (bios->fpxlatetableptr == 0x0) {
1697                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1698                                    "Pointer to flat panel translation table invalid\n");
1699                         return;
1700                 }
1701                 fpxlatetable = &bios->data[bios->fpxlatetableptr];
1702         /*      not yet used
1703                 lvdsmanufacturertable = &bios->data[bios->lvdsmanufacturerpointer];
1704                 fpxlatemanufacturertable = &bios->data[bios->fpxlatemanufacturertableptr];*/
1705
1706                 fpindex = fpxlatetable[fpstrapping];
1707         /*      not yet used
1708                 lvdsmanufacturerindex = fpxlatemanufacturertable[fpstrapping]; */
1709
1710                 if (fpindex > 0xf) {
1711                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1712                                    "Bad flat panel table index\n");
1713                         return;
1714                 }
1715                 break;
1716         case 0x20:      /* NV40+ */
1717                 headerlen = fptable[1];
1718                 recordlen = fptable[2]; // check this, or hardcode as 0x20
1719 /*              may be the wrong test, if there's a translation table
1720                 if (fpstrapping > fptable[3]) {
1721                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1722                                    "Flat panel strapping number too high\n");
1723                         return;
1724                 }*/
1725                 ofs = 0;
1726 /*              I don't know where the index for the table comes from in v2.0, so bail
1727                 break;*/
1728         default:
1729                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1730                            "FP Table revision not currently supported\n");
1731                 return;
1732         }
1733
1734         if (!(mode = xcalloc(1, sizeof(DisplayModeRec))))
1735                 return;
1736
1737         int modeofs = headerlen + recordlen * fpindex + ofs;
1738         mode->Clock = *(uint16_t *)&fptable[modeofs] * 10;
1739         mode->HDisplay = *(uint16_t *)&fptable[modeofs + 2];
1740         mode->HSyncStart = *(uint16_t *)&fptable[modeofs + 10] + 1;
1741         mode->HSyncEnd = *(uint16_t *)&fptable[modeofs + 12] + 1;
1742         mode->HTotal = *(uint16_t *)&fptable[modeofs + 14] + 1;
1743         mode->VDisplay = *(uint16_t *)&fptable[modeofs + 16];
1744         mode->VSyncStart = *(uint16_t *)&fptable[modeofs + 24] + 1;
1745         mode->VSyncEnd = *(uint16_t *)&fptable[modeofs + 26] + 1;
1746         mode->VTotal = *(uint16_t *)&fptable[modeofs + 28] + 1;
1747         mode->Flags |= (fptable[modeofs + 30] & 0x10) ? V_PHSYNC : V_NHSYNC;
1748         mode->Flags |= (fptable[modeofs + 30] & 0x1) ? V_PVSYNC : V_NVSYNC;
1749
1750         /* for version 1.0:
1751          * bytes 1-2 are "panel type", including bits on whether Colour/mono, single/dual link, and type (TFT etc.)
1752          * bytes 3-6 are bits per colour in RGBX
1753          * 11-12 is HDispEnd
1754          * 13-14 is HValid Start
1755          * 15-16 is HValid End
1756          * bytes 38-39 relate to spread spectrum settings
1757          * bytes 40-43 are something to do with PWM */
1758
1759         mode->prev = mode->next = NULL;
1760         mode->status = MODE_OK;
1761         mode->type = M_T_DRIVER | M_T_PREFERRED;
1762         xf86SetModeDefaultName(mode);
1763
1764 //      if (pNv->debug_modes) { this should exist
1765                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1766                            "Found flat panel mode in BIOS tables:\n");
1767                 xf86PrintModeline(pScrn->scrnIndex, mode);
1768 //      }
1769
1770         pNv->fp_native_mode = mode;
1771 }
1772
1773 static int parse_bit_display_tbl_entry(ScrnInfoPtr pScrn, bios_t *bios, bit_entry_t *bitentry)
1774 {
1775         uint16_t table;
1776         /* Parses the flat panel table segment that the bit entry points to.
1777          * Starting at bitentry->offset:
1778          *
1779          * offset + 0  (16 bits): FIXME table pointer
1780          * offset + 2  (16 bits): mode table pointer
1781          */
1782
1783         /* If it's not a laptop, you probably don't care about fptables */
1784         /* FIXME: detect mobile BIOS? */
1785
1786         NVPtr pNv = NVPTR(pScrn);
1787
1788         if (!pNv->Mobile)
1789                 return 1;
1790
1791         if (bitentry->length != 4) {
1792                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1793                            "Do not understand BIT display table entry.\n");
1794                 return 0;
1795         }
1796
1797         table = *((uint16_t *)(&bios->data[bitentry->offset]));
1798         bios->fptablepointer = *((uint16_t *)(&bios->data[bitentry->offset + 2]));
1799
1800         parse_fp_tables(pScrn, bios);
1801
1802         return 1;
1803 }
1804
1805 static unsigned int parse_bit_init_tbl_entry(ScrnInfoPtr pScrn, bios_t *bios, bit_entry_t *bitentry)
1806 {
1807         /* Parses the init table segment that the bit entry points to.
1808          * Starting at bitentry->offset: 
1809          * 
1810          * offset + 0  (16 bits): init script tables pointer
1811          * offset + 2  (16 bits): macro index table pointer
1812          * offset + 4  (16 bits): macro table pointer
1813          * offset + 6  (16 bits): condition table pointer
1814          * offset + 8  (16 bits): io condition table pointer
1815          * offset + 10 (16 bits): io flag condition table pointer
1816          * offset + 12 (16 bits): init function table pointer
1817          *
1818          * TODO:
1819          * * Are 'I' bit entries always of length 0xE?
1820          * 
1821          */
1822
1823         if (bitentry->length < 12) {
1824                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1825                            "Unable to recognize BIT init table entry.\n");
1826                 return 0;
1827         }
1828
1829         bios->init_script_tbls_ptr = *((uint16_t *)(&bios->data[bitentry->offset]));
1830         bios->macro_index_tbl_ptr = *((uint16_t *)(&bios->data[bitentry->offset + 2]));
1831         bios->macro_tbl_ptr = *((uint16_t *)(&bios->data[bitentry->offset + 4]));
1832         bios->condition_tbl_ptr = *((uint16_t *)(&bios->data[bitentry->offset + 6]));
1833         bios->io_condition_tbl_ptr = *((uint16_t *)(&bios->data[bitentry->offset + 8]));
1834         bios->io_flag_condition_tbl_ptr = *((uint16_t *)(&bios->data[bitentry->offset + 10]));
1835         bios->init_function_tbl_ptr = *((uint16_t *)(&bios->data[bitentry->offset + 12]));
1836
1837         parse_init_tables(pScrn, bios);
1838
1839         return 1;
1840 }
1841
1842 static unsigned int parse_bmp_table_pointers(ScrnInfoPtr pScrn, bios_t *bios, bit_entry_t *bitentry)
1843 {
1844         /* Parse the pointers for useful tables in the BMP structure, starting at
1845          * offset 75 from the ..NV. signature.
1846          *
1847          * First 7 pointers as for parse_bit_init_tbl_entry
1848          *
1849          * offset + 30: flat panel timings table pointer
1850          * offset + 32: flat panel strapping translation table pointer
1851          * offset + 42: LVDS manufacturer panel config table pointer
1852          * offset + 44: LVDS manufacturer strapping translation table pointer
1853          */
1854
1855         NVPtr pNv = NVPTR(pScrn);
1856
1857         if (!parse_bit_init_tbl_entry(pScrn, bios, bitentry))
1858                 return 0;
1859
1860         /* If it's not a laptop, you probably don't care about fptables */
1861         /* FIXME: detect mobile BIOS? */
1862         if (!pNv->Mobile)
1863                 return 1;
1864
1865         if (bitentry->length > 33) {
1866                 bios->fptablepointer = *((uint16_t *)(&bios->data[bitentry->offset + 30]));
1867                 bios->fpxlatetableptr = *((uint16_t *)(&bios->data[bitentry->offset + 32]));
1868         }
1869         if (bitentry->length > 45) {
1870                 bios->lvdsmanufacturerpointer = *((uint16_t *)(&bios->data[bitentry->offset + 42]));
1871                 bios->fpxlatemanufacturertableptr = *((uint16_t *)(&bios->data[bitentry->offset + 44]));
1872         }
1873
1874         parse_fp_tables(pScrn, bios);
1875
1876         return 1;
1877 }
1878
1879 static void parse_bit_structure(ScrnInfoPtr pScrn, bios_t *bios, unsigned int offset)
1880 {
1881         bit_entry_t *bitentry;
1882         char done = 0;
1883
1884         while (!done) {
1885                 bitentry = (bit_entry_t *) &bios->data[offset];
1886
1887                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1888                            "0x%04X: Found BIT command with id 0x%02X\n",
1889                            offset, bitentry->id[0]);
1890
1891                 switch (bitentry->id[0]) {
1892                 case 0:
1893                         /* id[0] = 0 and id[1] = 0 ==> end of BIT struture */
1894                         if (bitentry->id[1] == 0)
1895                                 done = 1;
1896                         break;
1897                 case 'D':
1898                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1899                                    "0x%04X: Found flat panel display table entry in BIT structure.\n", offset);
1900                         parse_bit_display_tbl_entry(pScrn, bios, bitentry);
1901                         break;
1902                 case 'I':
1903                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1904                                    "0x%04X: Found init table entry in BIT structure.\n", offset);
1905
1906                         parse_bit_init_tbl_entry(pScrn, bios, bitentry);
1907                         break;
1908                         
1909                         /* TODO: What kind of information does the other BIT entrys point to?
1910                          *       'P' entry is probably performance tables, but there are
1911                          *       quite a few others...
1912                          */
1913                 }
1914
1915                 offset += sizeof(bit_entry_t);
1916         }
1917 }
1918
1919 static void parse_pins_structure(ScrnInfoPtr pScrn, bios_t *bios, unsigned int offset)
1920 {
1921         int pins_version_major=bios->data[offset+5];
1922         int pins_version_minor=bios->data[offset+6];
1923         int init1 = bios->data[offset + 18] + (bios->data[offset + 19] * 256);
1924         int init2 = bios->data[offset + 20] + (bios->data[offset + 21] * 256);
1925         int init_size = bios->data[offset + 22] + (bios->data[offset + 23] * 256) + 1;
1926         int ram_tab;
1927
1928         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PINS version %d.%d\n",
1929                    pins_version_major, pins_version_minor);
1930
1931         /* checksum */
1932         if (nv_cksum(bios->data, offset, 8)) {
1933                 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "bad PINS checksum\n");
1934                 return;
1935         }
1936
1937         switch(pins_version_major) {
1938                 case 2:
1939                         ram_tab = init1-0x0010;
1940                         break;
1941                 case 3:
1942                 case 4:
1943                 case 5:
1944                         ram_tab = bios->data[offset + 24] + (bios->data[offset + 25] * 256);
1945                         break;
1946                 default:
1947                         return;
1948         }
1949         
1950         if ((pins_version_major==5)&&(pins_version_minor>=6)) {
1951                 /* VCO range info */
1952         }
1953
1954         if ((pins_version_major==5)&&(pins_version_minor>=16)) {
1955                 bit_entry_t bitentry;
1956
1957                 if (pins_version_minor == 0x10)
1958                         bitentry.length = 12; /* I've not seen this version, so be "long enough" */
1959                 else if (pins_version_minor < 0x14)
1960                         bitentry.length = 34;
1961                 else
1962                         bitentry.length = 48; /* versions after 0x14 are longer,
1963                                                  but extra contents unneeded ATM */
1964
1965                 bitentry.offset = offset + 75;
1966                 parse_bmp_table_pointers(pScrn, bios, &bitentry);
1967         } else {
1968                 /* TODO type1 script */
1969         }
1970 }
1971
1972 static unsigned int findstr(bios_t* bios, unsigned char *str, int len)
1973 {
1974         int i;
1975
1976         for (i = 2; i <= (bios->length - len); i++)
1977                 if (strncmp((char *)&bios->data[i], (char *)str, len) == 0)
1978                         return i;
1979
1980         return 0;
1981 }
1982
1983 static Bool parse_dcb_entry(uint8_t dcb_version, uint32_t conn, uint32_t conf, struct dcb_entry *entry)
1984 {
1985         if (dcb_version >= 0x20) {
1986                 entry->type = conn & 0xf;
1987                 entry->i2c_index = (conn >> 4) & 0xf;
1988                 entry->head = (conn >> 8) & 0xf;
1989                 entry->bus = (conn >> 16) & 0xf;
1990                 entry->or = (conn >> 24) & 0xf;
1991         } else if (dcb_version >= 0x14 ) {
1992                 // 1.4 needs more loving
1993                 entry->type = 0;
1994                 entry->i2c_index = 0;
1995                 entry->head = 0;
1996                 entry->bus = 0;
1997                 entry->or = 0;
1998                 return FALSE;
1999         } else {
2000                 // 1.2 needs more loving
2001                 entry->type = 0;
2002                 entry->i2c_index = 0;
2003                 entry->head = 0;
2004                 entry->bus = 0;
2005                 entry->or = 0;
2006                 return FALSE;
2007         }
2008
2009         return TRUE;
2010 }
2011
2012 static void
2013 read_dcb_i2c_table(ScrnInfoPtr pScrn, bios_t *bios, uint8_t dcb_version, uint16_t i2ctabptr)
2014 {
2015         NVPtr pNv = NVPTR(pScrn);
2016         uint8_t *i2ctable;
2017         uint8_t headerlen = 0;
2018         int i2c_entries;
2019         int recordoffset = 0, rdofs = 1, wrofs = 0;
2020         int i;
2021
2022         i2c_entries = MAX_NUM_DCB_ENTRIES;
2023         memset(pNv->dcb_table.i2c_read, 0, sizeof(pNv->dcb_table.i2c_read));
2024         memset(pNv->dcb_table.i2c_write, 0, sizeof(pNv->dcb_table.i2c_write));
2025
2026         i2ctable = &bios->data[i2ctabptr];
2027
2028         if (dcb_version >= 0x30) {
2029                 if (i2ctable[0] != dcb_version) { /* necessary? */
2030                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2031                                    "DCB I2C table version mismatch (%02X vs %02X)\n",
2032                                    i2ctable[0], dcb_version);
2033                         return;
2034                 }
2035                 headerlen = i2ctable[1];
2036                 i2c_entries = i2ctable[2];
2037                 if (i2ctable[0] >= 0x40) {
2038                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2039                                    "G80 DCB I2C table detected, arrgh\n"); /* they're plain weird */
2040                         return;
2041                 }
2042         }
2043         /* it's your own fault if you call this function on a DCB 1.1 BIOS */
2044         if (dcb_version < 0x14) {
2045                 recordoffset = 2;
2046                 rdofs = 0;
2047                 wrofs = 1;
2048         }
2049
2050         for (i = 0; i < i2c_entries; i++) {
2051                 if (i2ctable[headerlen + 4 * i + 3] != 0xff) {
2052                         pNv->dcb_table.i2c_read[i] = i2ctable[headerlen + recordoffset + rdofs + 4 * i];
2053                         pNv->dcb_table.i2c_write[i] = i2ctable[headerlen + recordoffset + wrofs + 4 * i];
2054                 }
2055         }
2056 }
2057
2058 #define G5_NV43_FIXED_LOC 0xe31b
2059
2060 static unsigned int parse_dcb_table(ScrnInfoPtr pScrn, bios_t *bios)
2061 {
2062         NVPtr pNv = NVPTR(pScrn);
2063         uint16_t dcbptr, i2ctabptr = 0;
2064         Bool is_g5_nv43 = FALSE;
2065         uint8_t *dcbtable;
2066         uint8_t dcb_version, headerlen = 0x4, entries = MAX_NUM_DCB_ENTRIES;
2067         Bool configblock = TRUE;
2068         int recordlength = 8, confofs = 4;
2069         int i;
2070
2071         pNv->dcb_table.entries = 0;
2072
2073         /* get the offset from 0x36 */
2074         dcbptr = *(uint16_t *)&bios->data[0x36];
2075
2076         if (dcbptr == 0x0) {
2077                 if ((pNv->Chipset & 0x0ff0) == CHIPSET_NV43) {
2078                         dcbptr = G5_NV43_FIXED_LOC;
2079                         is_g5_nv43 = TRUE;
2080                 } else {
2081                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2082                                    "No Display Configuration Block pointer found\n");
2083                         return 0;
2084                 }
2085         }
2086
2087         dcbtable = &bios->data[dcbptr];
2088
2089         /* get DCB version */
2090         dcb_version = dcbtable[0];
2091         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2092                    "Display Configuration Block version %d.%d found\n",
2093                    dcb_version >> 4, dcb_version & 0xf);
2094
2095         if (dcb_version >= 0x20) { /* NV17+ */
2096                 uint32_t sig;
2097
2098                 if (dcb_version >= 0x30) { /* NV40+ */
2099                         headerlen = dcbtable[1];
2100                         entries = dcbtable[2];
2101                         i2ctabptr = *(uint16_t *)&dcbtable[4];
2102                         sig = *(uint32_t *)&dcbtable[6];
2103
2104                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2105                                    "DCB header length %02X, with %02X possible entries\n",
2106                                    headerlen, entries);
2107                 } else {
2108                         /* dcb_block_count = *(dcbtable[1]); */
2109                         i2ctabptr = *(uint16_t *)&dcbtable[2];
2110                         sig = *(uint32_t *)&dcbtable[4];
2111                         headerlen = 8;
2112                 }
2113
2114                 if (sig != 0x4edcbdcb) {
2115                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2116                                    "Bad Display Configuration Block signature (%08X)\n", sig);
2117                         return 0;
2118                 }
2119         } else if (dcb_version >= 0x14) { /* some NV15/16, and NV11+ */
2120                 char sig[8];
2121
2122                 memset(sig, 0, 8);
2123                 strncpy(sig, (char *)&dcbtable[-7], 7);
2124                 /* dcb_block_count = *(dcbtable[1]); */
2125                 i2ctabptr = *(uint16_t *)&dcbtable[2];
2126                 recordlength = 10;
2127                 confofs = 6;
2128
2129                 if (strcmp(sig, "DEV_REC")) {
2130                         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2131                                    "Bad Display Configuration Block signature (%s)\n", sig);
2132                         return 0;
2133                 }
2134         } else if (dcb_version >= 0x12) { /* some NV6/10, and NV15+ */
2135                 /* dcb_block_count = *(dcbtable[1]); */
2136                 i2ctabptr = *(uint16_t *)&dcbtable[2];
2137                 configblock = FALSE;
2138         } else {        /* NV5+, maybe NV4 */
2139                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2140                            "Structure of Display Configuration Blocks prior to version 1.2 unknown\n");
2141                 return 0;
2142         }
2143
2144         if (entries >= MAX_NUM_DCB_ENTRIES)
2145                 entries = MAX_NUM_DCB_ENTRIES;
2146
2147         for (i = 0; i < entries; i++) {
2148                 uint32_t connection, config = 0;
2149
2150                 if (is_g5_nv43) {
2151                         connection = __bswap_32(*(uint32_t *)&dcbtable[headerlen + recordlength * i]);
2152                         if (configblock)
2153                                 config = __bswap_32(*(uint32_t *)&dcbtable[headerlen + confofs + recordlength * i]);
2154                 } else {
2155                         connection = *(uint32_t *)&dcbtable[headerlen + recordlength * i];
2156                         if (configblock)
2157                                 config = *(uint32_t *)&dcbtable[headerlen + confofs + recordlength * i];
2158                 }
2159
2160                 /* I think this is a good descriminator, but I don't understand
2161                  * pre v2.0 DCBs so well, so maybe those need testing against
2162                  * 0xffffffff */
2163                 /* Should we allow discontinuous DCBs? Certainly DCB I2C tables
2164                  * can be discontinuous */
2165                 if ((connection & 0x0f000000) == 0x0f000000) /* end of records */
2166                         break;
2167
2168                 ErrorF("Raw DCB entry %d: %08x\n", i, connection);
2169                 if (!parse_dcb_entry(dcb_version, connection, config, &pNv->dcb_table.entry[i]))
2170                         break;
2171         }
2172         pNv->dcb_table.entries = i;
2173
2174         /* the G5 6600 uses a relative address */
2175         if (is_g5_nv43)
2176                 i2ctabptr += G5_NV43_FIXED_LOC;
2177
2178         read_dcb_i2c_table(pScrn, bios, dcb_version, i2ctabptr);
2179
2180         return pNv->dcb_table.entries;
2181 }
2182
2183 unsigned int NVParseBios(ScrnInfoPtr pScrn)
2184 {
2185         unsigned int bit_offset;
2186         bios_t bios;
2187         bios.data=NULL;
2188         bios.fptablepointer = 0;
2189         uint8_t nv_signature[]={0xff,0x7f,'N','V',0x0};
2190         uint8_t bit_signature[]={'B','I','T'};
2191         NVPtr pNv;
2192         pNv = NVPTR(pScrn);
2193
2194         pNv->dcb_table.entries = 0;
2195         pNv->fp_native_mode = NULL;
2196
2197         pNv->VBIOS = xalloc(64 * 1024);
2198         if (!NVShadowVBIOS(pScrn, pNv->VBIOS)) {
2199                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2200                            "No valid BIOS image found.\n");
2201                 xfree(pNv->VBIOS);
2202                 return 0;
2203         }
2204         bios.data = (uint8_t *)pNv->VBIOS;
2205         bios.length = bios.data[2] * 512;
2206         if (bios.length > NV_PROM_SIZE)
2207                 bios.length = NV_PROM_SIZE;
2208
2209         /* check for known signatures */
2210         if ((bit_offset = findstr(&bios, bit_signature, sizeof(bit_signature)))) {
2211                 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIT signature found.\n");
2212                 parse_bit_structure(pScrn, &bios, bit_offset + 4);
2213         } else if ((bit_offset = findstr(&bios, nv_signature, sizeof(nv_signature)))) {
2214                 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV signature found.\n");
2215                 parse_pins_structure(pScrn, &bios, bit_offset);
2216         } else
2217                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2218                            "No known script signature found.\n");
2219
2220         /* parse Display Configuration Block (DCB) table */
2221         if (parse_dcb_table(pScrn, &bios))
2222                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2223                            "Found %d entries in DCB.\n", pNv->dcb_table.entries);
2224
2225         return 1;
2226 }