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