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