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