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