2 * Copyright 2005-2006 Erik Waling
3 * Copyright 2006 Stephane Marchesin
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:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
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
24 #include "nv_include.h"
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
41 static int crtchead = 0;
48 static uint16_t le16_to_cpu(const uint16_t x)
50 #if X_BYTE_ORDER == X_BIG_ENDIAN
57 static uint32_t le32_to_cpu(const uint32_t x)
59 #if X_BYTE_ORDER == X_BIG_ENDIAN
66 static Bool nv_cksum(const uint8_t *data, unsigned int length)
68 /* there's a few checksums in the BIOS, so here's a generic checking function */
72 for (i = 0; i < length; i++)
81 static int NVValidVBIOS(ScrnInfoPtr pScrn, const uint8_t *data)
83 /* check for BIOS signature */
84 if (!(data[0] == 0x55 && data[1] == 0xAA)) {
85 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
86 "... BIOS signature not found\n");
90 if (nv_cksum(data, data[2] * 512)) {
91 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
92 "... BIOS checksum invalid\n");
93 /* probably ought to set a do_not_execute flag for table parsing here,
94 * assuming most BIOSen are valid */
97 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "... appears to be valid\n");
102 static void NVShadowVBIOS_PROM(ScrnInfoPtr pScrn, uint8_t *data)
104 NVPtr pNv = NVPTR(pScrn);
107 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
108 "Attempting to locate BIOS image in PROM\n");
110 /* enable ROM access */
111 nvWriteMC(pNv, 0x1850, 0x0);
112 for (i = 0; i < NV_PROM_SIZE; i++) {
113 /* according to nvclock, we need that to work around a 6600GT/6800LE bug */
114 data[i] = pNv->PROM[i];
115 data[i] = pNv->PROM[i];
116 data[i] = pNv->PROM[i];
117 data[i] = pNv->PROM[i];
118 data[i] = pNv->PROM[i];
120 /* disable ROM access */
121 nvWriteMC(pNv, 0x1850, 0x1);
124 static void NVShadowVBIOS_PRAMIN(ScrnInfoPtr pScrn, uint32_t *data)
126 NVPtr pNv = NVPTR(pScrn);
127 const uint32_t *pramin = (uint32_t *)&pNv->REGS[NV_PRAMIN_ROM_OFFSET/4];
128 uint32_t old_bar0_pramin = 0;
130 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
131 "Attempting to locate BIOS image in PRAMIN\n");
133 if (pNv->Architecture >= NV_ARCH_50) {
136 vbios_vram = (pNv->REGS[0x619f04/4] & ~0xff) << 8;
138 vbios_vram = pNv->REGS[0x1700/4] << 16;
139 vbios_vram += 0xf0000;
142 old_bar0_pramin = pNv->REGS[0x1700/4];
143 pNv->REGS[0x1700/4] = vbios_vram >> 16;
146 memcpy(data, pramin, NV_PROM_SIZE);
148 if (pNv->Architecture >= NV_ARCH_50) {
149 pNv->REGS[0x1700/4] = old_bar0_pramin;
153 static Bool NVShadowVBIOS(ScrnInfoPtr pScrn, uint8_t *data)
155 NVShadowVBIOS_PROM(pScrn, data);
156 if (NVValidVBIOS(pScrn, data) == 2)
159 NVShadowVBIOS_PRAMIN(pScrn, (uint32_t *)data);
160 if (NVValidVBIOS(pScrn, data))
171 int length_multiplier;
172 Bool (*handler)(ScrnInfoPtr pScrn, bios_t *, uint16_t, init_exec_t *);
181 static void parse_init_table(ScrnInfoPtr pScrn, bios_t *bios, unsigned int offset, init_exec_t *iexec);
183 #define MACRO_INDEX_SIZE 2
185 #define CONDITION_SIZE 12
186 #define IO_FLAG_CONDITION_SIZE 9
194 static int nv_valid_reg(uint32_t reg)
196 #define WITHIN(x,y,z) ((x>=y)&&(x<y+z))
197 if (WITHIN(reg,NV_PRAMIN_OFFSET,NV_PRAMIN_SIZE))
199 if (WITHIN(reg,NV_PCRTC0_OFFSET,NV_PCRTC0_SIZE))
201 if (WITHIN(reg,NV_PRAMDAC0_OFFSET,NV_PRAMDAC0_SIZE))
203 if (WITHIN(reg,NV_PFB_OFFSET,NV_PFB_SIZE))
205 if (WITHIN(reg,NV_PFIFO_OFFSET,NV_PFIFO_SIZE))
207 if (WITHIN(reg,NV_PGRAPH_OFFSET,NV_PGRAPH_SIZE))
209 if (WITHIN(reg,NV_PEXTDEV_OFFSET,NV_PEXTDEV_SIZE))
211 if (WITHIN(reg,NV_PTIMER_OFFSET,NV_PTIMER_SIZE))
213 if (WITHIN(reg,NV_PVIDEO_OFFSET,NV_PVIDEO_SIZE))
215 if (WITHIN(reg,NV_PMC_OFFSET,NV_PMC_SIZE))
217 if (WITHIN(reg,NV_FIFO_OFFSET,NV_FIFO_SIZE))
219 if (WITHIN(reg,NV_PCIO0_OFFSET,NV_PCIO0_SIZE))
221 if (WITHIN(reg,NV_PDIO0_OFFSET,NV_PDIO0_SIZE))
223 if (WITHIN(reg,NV_PVIO_OFFSET,NV_PVIO_SIZE))
225 if (WITHIN(reg,NV_PROM_OFFSET,NV_PROM_SIZE))
227 if (WITHIN(reg,NV_PRAMIN_ROM_OFFSET,NV_PROM_SIZE))
233 static void nv32_rd(ScrnInfoPtr pScrn, uint32_t reg, uint32_t *data)
235 NVPtr pNv = NVPTR(pScrn);
237 if (!nv_valid_reg(reg)) {
238 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
239 "========= unknown reg 0x%08X ==========\n", reg);
242 *data = pNv->REGS[reg/4];
244 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
245 " Read: Reg: 0x%08X, Data: 0x%08X\n", reg, *data);
248 static int nv32_wr(ScrnInfoPtr pScrn, uint32_t reg, uint32_t data)
250 NVPtr pNv = NVPTR(pScrn);
251 if (DEBUGLEVEL >= 8) {
253 nv32_rd(pScrn, reg, &tmp);
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);
264 if (pNv->VBIOS.execute) {
266 NVPtr pNv = NVPTR(pScrn);
267 pNv->REGS[reg/4] = data;
273 static void nv_port_rd(ScrnInfoPtr pScrn, uint16_t port, uint8_t index, uint8_t *data)
275 NVPtr pNv = NVPTR(pScrn);
276 volatile uint8_t *ptr = crtchead ? pNv->PCIO1 : pNv->PCIO0;
278 VGA_WR08(ptr, port, index);
279 *data = VGA_RD08(ptr, port + 1);
282 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
283 " Indexed read: Port: 0x%04X, Index: 0x%02X, Head: 0x%02X, Data: 0x%02X\n",
284 port, index, crtchead, *data);
287 static void nv_port_wr(ScrnInfoPtr pScrn, uint16_t port, uint8_t index, uint8_t data)
289 NVPtr pNv = NVPTR(pScrn);
290 volatile uint8_t *ptr;
292 /* The current head is maintained in a file scope variable crtchead.
293 * We trap changes to CRTCX_OWNER and update the head variable
294 * and hence the register set written.
295 * As CRTCX_OWNER only exists on CRTC0, we update crtchead to head0
296 * in advance of the write, and to head1 after the write
298 if (port == CRTC_INDEX_COLOR && index == NV_VGA_CRTCX_OWNER && data != NV_VGA_CRTCX_OWNER_HEADB)
300 ptr = crtchead ? pNv->PCIO1 : pNv->PCIO0;
302 if (DEBUGLEVEL >= 8) {
304 nv_port_rd(pScrn, port, index, &tmp);
307 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
308 " Indexed write: Port: 0x%04X, Index: 0x%02X, Head: 0x%02X, Data: 0x%02X\n",
309 port, index, crtchead, data);
311 if (pNv->VBIOS.execute) {
313 VGA_WR08(ptr, port, index);
314 VGA_WR08(ptr, port + 1, data);
317 if (port == CRTC_INDEX_COLOR && index == NV_VGA_CRTCX_OWNER && data == NV_VGA_CRTCX_OWNER_HEADB)
321 static Bool io_flag_condition(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, uint8_t cond)
323 /* The IO flag condition entry has 2 bytes for the CRTC port; 1 byte
324 * for the CRTC index; 1 byte for the mask to apply to the value
325 * retrieved from the CRTC; 1 byte for the shift right to apply to the
326 * masked CRTC value; 2 bytes for the offset to the flag array, to
327 * which the shifted value is added; 1 byte for the mask applied to the
328 * value read from the flag array; and 1 byte for the value to compare
329 * against the masked byte from the flag table.
332 uint16_t condptr = bios->io_flag_condition_tbl_ptr + cond * IO_FLAG_CONDITION_SIZE;
333 uint16_t crtcport = le16_to_cpu(*((uint16_t *)(&bios->data[condptr])));
334 uint8_t crtcindex = bios->data[condptr + 2];
335 uint8_t mask = bios->data[condptr + 3];
336 uint8_t shift = bios->data[condptr + 4];
337 uint16_t flagarray = le16_to_cpu(*((uint16_t *)(&bios->data[condptr + 5])));
338 uint8_t flagarraymask = bios->data[condptr + 7];
339 uint8_t cmpval = bios->data[condptr + 8];
343 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
344 "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, Shift: 0x%02X, FlagArray: 0x%04X, FAMask: 0x%02X, Cmpval: 0x%02X\n",
345 offset, crtcport, crtcindex, mask, shift, flagarray, flagarraymask, cmpval);
347 nv_port_rd(pScrn, crtcport, crtcindex, &data);
349 data = bios->data[flagarray + ((data & mask) >> shift)];
350 data &= flagarraymask;
353 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
354 "0x%04X: Checking if 0x%02X equals 0x%02X\n",
355 offset, data, cmpval);
363 static Bool init_prog(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
365 /* INIT_PROG opcode: 0x31
367 * offset (8 bit): opcode
368 * offset + 1 (32 bit): reg
369 * offset + 5 (32 bit): and mask
370 * offset + 9 (8 bit): shift right
371 * offset + 10 (8 bit): number of configurations
372 * offset + 11 (32 bit): register
373 * offset + 15 (32 bit): configuration 1
376 * Starting at offset + 15 there are "number of configurations"
377 * 32 bit values. To find out which configuration value to use
378 * read "CRTC reg" on the CRTC controller with index "CRTC index"
379 * and bitwise AND this value with "and mask" and then bit shift the
380 * result "shift right" bits to the right.
381 * Assign "register" with appropriate configuration value.
384 CARD32 reg = *((CARD32 *) (&bios->data[offset + 1]));
385 CARD32 and = *((CARD32 *) (&bios->data[offset + 5]));
386 CARD8 shiftr = *((CARD8 *) (&bios->data[offset + 9]));
387 CARD8 nr = *((CARD8 *) (&bios->data[offset + 10]));
388 CARD32 reg2 = *((CARD32 *) (&bios->data[offset + 11]));
390 CARD32 configval, tmp;
392 if (iexec->execute) {
393 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: REG: 0x%04X\n", offset,
396 nv32_rd(pScrn, reg, &tmp);
397 configuration = (tmp & and) >> shiftr;
399 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CONFIGURATION TO USE: 0x%02X\n",
400 offset, configuration);
402 if (configuration <= nr) {
405 *((CARD32 *) (&bios->data[offset + 15 + configuration * 4]));
407 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: REG: 0x%08X, VALUE: 0x%08X\n", offset,
410 nv32_rd(pScrn, reg2, &tmp);
411 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%08X\n",
413 nv32_wr(pScrn, reg2, configval);
419 static Bool init_io_restrict_prog(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
421 /* INIT_IO_RESTRICT_PROG opcode: 0x32 ('2')
423 * offset (8 bit): opcode
424 * offset + 1 (16 bit): CRTC port
425 * offset + 3 (8 bit): CRTC index
426 * offset + 4 (8 bit): mask
427 * offset + 5 (8 bit): shift
428 * offset + 6 (8 bit): count
429 * offset + 7 (32 bit): register
430 * offset + 11 (32 bit): configuration 1
433 * Starting at offset + 11 there are "count" 32 bit values.
434 * To find out which value to use read index "CRTC index" on "CRTC port",
435 * AND this value with "mask" and then bit shift right "shift" bits.
436 * Read the appropriate value using this index and write to "register"
439 uint16_t crtcport = le16_to_cpu(*((uint16_t *)(&bios->data[offset + 1])));
440 uint8_t crtcindex = bios->data[offset + 3];
441 uint8_t mask = bios->data[offset + 4];
442 uint8_t shift = bios->data[offset + 5];
443 uint8_t count = bios->data[offset + 6];
444 uint32_t reg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 7])));
452 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
453 "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, Shift: 0x%02X, Count: 0x%02X, Reg: 0x%08X\n",
454 offset, crtcport, crtcindex, mask, shift, count, reg);
456 nv_port_rd(pScrn, crtcport, crtcindex, &config);
457 config = (config & mask) >> shift;
458 if (config > count) {
459 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
460 "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
461 offset, config, count);
465 configval = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 11 + config * 4])));
468 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
469 "0x%04X: Writing config %02X\n", offset, config);
471 nv32_wr(pScrn, reg, configval);
476 static Bool init_repeat(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
478 /* INIT_REPEAT opcode: 0x33 ('3')
480 * offset (8 bit): opcode
481 * offset + 1 (8 bit): count
483 * Execute script following this opcode up to INIT_REPEAT_END
487 uint8_t count = bios->data[offset + 1];
490 /* no iexec->execute check by design */
492 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
493 "0x%04X: REPEATING FOLLOWING SEGMENT %d TIMES.\n",
496 iexec->repeat = TRUE;
498 /* count - 1, as the script block will execute once when we leave this
499 * opcode -- this is compatible with bios behaviour as:
500 * a) the block is always executed at least once, even if count == 0
501 * b) the bios interpreter skips to the op following INIT_END_REPEAT,
504 for (i = 0; i < count - 1; i++)
505 parse_init_table(pScrn, bios, offset + 2, iexec);
507 iexec->repeat = FALSE;
512 static Bool init_io_restrict_pll(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
514 /* INIT_IO_RESTRICT_PLL opcode: 0x34 ('4')
516 * offset (8 bit): opcode
517 * offset + 1 (16 bit): CRTC port
518 * offset + 3 (8 bit): CRTC index
519 * offset + 4 (8 bit): mask
520 * offset + 5 (8 bit): shift
521 * offset + 6 (8 bit): IO flag condition index
522 * offset + 7 (8 bit): count
523 * offset + 8 (32 bit): register
524 * offset + 12 (16 bit): frequency 1
527 * Starting at offset + 12 there are "count" 16 bit frequencies (10kHz).
528 * Set PLL register "register" to coefficients for frequency n,
529 * selected by reading index "CRTC index" of "CRTC port" ANDed with
530 * "mask" and shifted right by "shift". If "IO flag condition index" > 0,
531 * and condition met, double frequency before setting it.
534 uint16_t crtcport = le16_to_cpu(*((uint16_t *)(&bios->data[offset + 1])));
535 uint8_t crtcindex = bios->data[offset + 3];
536 uint8_t mask = bios->data[offset + 4];
537 uint8_t shift = bios->data[offset + 5];
538 int8_t io_flag_condition_idx = bios->data[offset + 6];
539 uint8_t count = bios->data[offset + 7];
540 uint32_t reg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 8])));
548 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
549 "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",
550 offset, crtcport, crtcindex, mask, shift, io_flag_condition_idx, count, reg);
552 nv_port_rd(pScrn, crtcport, crtcindex, &config);
553 config = (config & mask) >> shift;
554 if (config > count) {
555 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
556 "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
557 offset, config, count);
561 freq = le16_to_cpu(*((uint16_t *)(&bios->data[offset + 12 + config * 2])));
563 if (io_flag_condition_idx > 0) {
564 if (io_flag_condition(pScrn, bios, offset, io_flag_condition_idx)) {
565 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
566 "0x%04X: CONDITION FULFILLED - FREQ DOUBLED\n", offset);
569 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
570 "0x%04X: CONDITION IS NOT FULFILLED. FREQ UNCHANGED\n", offset);
574 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
575 "0x%04X: Reg: 0x%08X, Config: 0x%02X, Freq: %d0kHz\n",
576 offset, reg, config, freq);
578 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
583 configval = 0x01014E07;
586 configval = 0x13030E02;
593 static Bool init_end_repeat(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
595 /* INIT_END_REPEAT opcode: 0x36 ('6')
597 * offset (8 bit): opcode
599 * Marks the end of the block for INIT_REPEAT to repeat
602 /* no iexec->execute check by design */
604 /* iexec->repeat flag necessary to go past INIT_END_REPEAT opcode when
605 * we're not in repeat mode
613 static Bool init_copy(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
615 /* INIT_COPY opcode: 0x37 ('7')
617 * offset (8 bit): opcode
618 * offset + 1 (32 bit): register
619 * offset + 5 (8 bit): shift
620 * offset + 6 (8 bit): srcmask
621 * offset + 7 (16 bit): CRTC port
622 * offset + 9 (8 bit): CRTC index
623 * offset + 10 (8 bit): mask
625 * Read index "CRTC index" on "CRTC port", AND with "mask", OR with
626 * (REGVAL("register") >> "shift" & "srcmask") and write-back to CRTC port
629 uint32_t reg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 1])));
630 uint8_t shift = bios->data[offset + 5];
631 uint8_t srcmask = bios->data[offset + 6];
632 uint16_t crtcport = le16_to_cpu(*((uint16_t *)(&bios->data[offset + 7])));
633 uint8_t crtcindex = bios->data[offset + 9];
634 uint8_t mask = bios->data[offset + 10];
642 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
643 "0x%04X: Reg: 0x%08X, Shift: 0x%02X, SrcMask: 0x%02X, Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X\n",
644 offset, reg, shift, srcmask, crtcport, crtcindex, mask);
646 nv32_rd(pScrn, reg, &data);
651 data <<= (0x100 - shift);
655 nv_port_rd(pScrn, crtcport, crtcindex, &crtcdata);
656 crtcdata = (crtcdata & mask) | (uint8_t)data;
657 nv_port_wr(pScrn, crtcport, crtcindex, crtcdata);
662 static Bool init_not(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
664 /* INIT_NOT opcode: 0x38 ('8')
666 * offset (8 bit): opcode
668 * Invert the current execute / no-execute condition (i.e. "else")
671 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
672 "0x%04X: ------ SKIPPING FOLLOWING COMMANDS ------\n", offset);
674 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
675 "0x%04X: ------ EXECUTING FOLLOWING COMMANDS ------\n", offset);
677 iexec->execute = !iexec->execute;
681 static Bool init_io_flag_condition(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
683 /* INIT_IO_FLAG_CONDITION opcode: 0x39 ('9')
685 * offset (8 bit): opcode
686 * offset + 1 (8 bit): condition number
688 * Check condition "condition number" in the IO flag condition table.
689 * If condition not met skip subsequent opcodes until condition
690 * is inverted (INIT_NOT), or we hit INIT_RESUME
693 uint8_t cond = bios->data[offset + 1];
698 if (io_flag_condition(pScrn, bios, offset, cond))
699 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
700 "0x%04X: CONDITION FULFILLED - CONTINUING TO EXECUTE\n", offset);
702 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
703 "0x%04X: CONDITION IS NOT FULFILLED.\n", offset);
704 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
705 "0x%04X: ------ SKIPPING FOLLOWING COMMANDS ------\n", offset);
706 iexec->execute = FALSE;
712 Bool init_idx_addr_latched(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
714 /* INIT_INDEX_ADDRESS_LATCHED opcode: 0x49 ('I')
716 * offset (8 bit): opcode
717 * offset + 1 (32 bit): control register
718 * offset + 5 (32 bit): data register
719 * offset + 9 (32 bit): mask
720 * offset + 13 (32 bit): data
721 * offset + 17 (8 bit): count
722 * offset + 18 (8 bit): address 1
723 * offset + 19 (8 bit): data 1
726 * For each of "count" address and data pairs, write "data n" to "data register",
727 * read the current value of "control register", and write it back once ANDed
728 * with "mask", ORed with "data", and ORed with "address n"
731 uint32_t controlreg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 1])));
732 uint32_t datareg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 5])));
733 uint32_t mask = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 9])));
734 uint32_t data = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 13])));
735 uint8_t count = bios->data[offset + 17];
743 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
744 "0x%04X: ControlReg: 0x%08X, DataReg: 0x%08X, Mask: 0x%08X, Data: 0x%08X, Count: 0x%02X\n",
745 offset, controlreg, datareg, mask, data, count);
747 for (i = 0; i < count; i++) {
748 uint8_t instaddress = bios->data[offset + 18 + i * 2];
749 uint8_t instdata = bios->data[offset + 19 + i * 2];
752 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
753 "0x%04X: Address: 0x%02X, Data: 0x%02X\n", offset, instaddress, instdata);
755 nv32_wr(pScrn, datareg, instdata);
757 nv32_rd(pScrn, controlreg, &value);
758 value = (value & mask) | data | instaddress;
760 nv32_wr(pScrn, controlreg, value);
766 static Bool init_io_restrict_pll2(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
768 /* INIT_IO_RESTRICT_PLL2 opcode: 0x4A ('J')
770 * offset (8 bit): opcode
771 * offset + 1 (16 bit): CRTC port
772 * offset + 3 (8 bit): CRTC index
773 * offset + 4 (8 bit): mask
774 * offset + 5 (8 bit): shift
775 * offset + 6 (8 bit): count
776 * offset + 7 (32 bit): register
777 * offset + 11 (32 bit): frequency 1
780 * Starting at offset + 11 there are "count" 32 bit frequencies (kHz).
781 * Set PLL register "register" to coefficients for frequency n,
782 * selected by reading index "CRTC index" of "CRTC port" ANDed with
783 * "mask" and shifted right by "shift".
786 uint16_t crtcport = le16_to_cpu(*((uint16_t *)(&bios->data[offset + 1])));
787 uint8_t crtcindex = bios->data[offset + 3];
788 uint8_t mask = bios->data[offset + 4];
789 uint8_t shift = bios->data[offset + 5];
790 uint8_t count = bios->data[offset + 6];
791 uint32_t reg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 7])));
799 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
800 "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, Shift: 0x%02X, Count: 0x%02X, Reg: 0x%08X\n",
801 offset, crtcport, crtcindex, mask, shift, count, reg);
806 nv_port_rd(pScrn, crtcport, crtcindex, &config);
807 config = (config & mask) >> shift;
808 if (config > count) {
809 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
810 "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
811 offset, config, count);
815 freq = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 11 + config * 4])));
818 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
819 "0x%04X: Reg: 0x%08X, Config: 0x%02X, Freq: %dkHz\n",
820 offset, reg, config, freq);
822 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
827 static Bool init_pll2(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
829 /* INIT_PLL2 opcode: 0x4B ('K')
831 * offset (8 bit): opcode
832 * offset + 1 (32 bit): register
833 * offset + 5 (32 bit): freq
835 * Set PLL register "register" to coefficients for frequency "freq"
838 uint32_t reg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 1])));
839 uint32_t freq = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 5])));
845 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
846 "0x%04X: Reg: 0x%04X, Freq: %dkHz\n",
849 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
854 Bool init_50(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
856 /* INIT_50 opcode: 0x50 ('P')
858 * offset (8 bit): opcode
859 * offset + 1 (8 bit): magic lookup value
860 * offset + 2 (8 bit): count
861 * offset + 3 (8 bit): addr 1
862 * offset + 4 (8 bit): data 1
865 * For each of "count" TMDS address and data pairs write "data n" to "addr n"
866 * "magic lookup value" (mlv) determines which TMDS base address is used:
867 * For mlv < 80, it is an index into a table of TMDS base addresses
868 * For mlv == 80 use the "or" value of the dcb_entry indexed by CR58 for CR57 = 0
869 * to index a table of offsets to the basic 0x6808b0 address
870 * For mlv == 81 use the "or" value of the dcb_entry indexed by CR58 for CR57 = 0
871 * to index a table of offsets to the basic 0x6808b0 address, and then flip the offset by 8
873 NVPtr pNv = NVPTR(pScrn);
874 uint8_t mlv = bios->data[offset + 1];
875 uint8_t count = bios->data[offset + 2];
879 int pramdac_offset[13] = {0, 0, 0x8, 0, 0x2000, 0, 0, 0, 0x2008, 0, 0, 0, 0x2000};
880 uint32_t pramdac_table[4] = {0x6808b0, 0x6808b8, 0x6828b0, 0x6828b8};
886 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
887 "0x%04X: MagicLookupValue: 0x%02X, Count: 0x%02X\n",
890 /* here we assume that the DCB table has already been parsed */
893 /* This register needs to written for correct output */
894 nv_port_wr(pScrn, CRTC_INDEX_COLOR, 0x57, 0);
895 nv_port_rd(pScrn, CRTC_INDEX_COLOR, 0x58, &dcb_entry);
896 if (dcb_entry > pNv->dcb_table.entries) {
897 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
898 "0x%04X: CR58 doesn't have a valid DCB entry currently (%02X)\n",
902 dacoffset = pramdac_offset[pNv->dcb_table.entry[dcb_entry].or];
905 reg = 0x6808b0 + dacoffset;
907 if (mlv > (sizeof(pramdac_table) / sizeof(uint32_t))) {
908 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
909 "0x%04X: Magic Lookup Value too big (%02X)\n", offset, mlv);
912 reg = pramdac_table[mlv];
915 for (i = 0; i < count; i++) {
916 uint8_t tmds_addr = bios->data[offset + 3 + i * 2];
917 uint8_t tmds_data = bios->data[offset + 4 + i * 2];
919 nv32_wr(pScrn, reg + 4, tmds_data);
920 nv32_wr(pScrn, reg, tmds_addr);
926 Bool init_cr_idx_adr_latch(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
928 /* INIT_CR_INDEX_ADDRESS_LATCHED opcode: 0x51 ('Q')
930 * offset (8 bit): opcode
931 * offset + 1 (8 bit): CRTC index1
932 * offset + 2 (8 bit): CRTC index2
933 * offset + 3 (8 bit): baseaddr
934 * offset + 4 (8 bit): count
935 * offset + 5 (8 bit): data 1
938 * For each of "count" address and data pairs, write "baseaddr + n" to
939 * "CRTC index1" and "data n" to "CRTC index2"
940 * Once complete, restore initial value read from "CRTC index1"
942 uint8_t crtcindex1 = bios->data[offset + 1];
943 uint8_t crtcindex2 = bios->data[offset + 2];
944 uint8_t baseaddr = bios->data[offset + 3];
945 uint8_t count = bios->data[offset + 4];
946 uint8_t oldaddr, data;
953 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
954 "0x%04X: Index1: 0x%02X, Index2: 0x%02X, BaseAddr: 0x%02X, Count: 0x%02X\n",
955 offset, crtcindex1, crtcindex2, baseaddr, count);
957 nv_port_rd(pScrn, CRTC_INDEX_COLOR, crtcindex1, &oldaddr);
959 for (i = 0; i < count; i++) {
960 nv_port_wr(pScrn, CRTC_INDEX_COLOR, crtcindex1, baseaddr + i);
962 data = bios->data[offset + 5 + i];
963 nv_port_wr(pScrn, CRTC_INDEX_COLOR, crtcindex2, data);
966 nv_port_wr(pScrn, CRTC_INDEX_COLOR, crtcindex1, oldaddr);
971 Bool init_cr(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
973 /* INIT_CR opcode: 0x52 ('R')
975 * offset (8 bit): opcode
976 * offset + 1 (8 bit): CRTC index
977 * offset + 2 (8 bit): mask
978 * offset + 3 (8 bit): data
980 * Assign the value of at "CRTC index" ANDed with mask and ORed with data
981 * back to "CRTC index"
984 uint8_t crtcindex = bios->data[offset + 1];
985 uint8_t mask = bios->data[offset + 2];
986 uint8_t data = bios->data[offset + 3];
993 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
994 "0x%04X: Index: 0x%02X, Mask: 0x%02X, Data: 0x%02X\n",
995 offset, crtcindex, mask, data);
997 nv_port_rd(pScrn, CRTC_INDEX_COLOR, crtcindex, &value);
999 value = (value & mask) | data;
1001 nv_port_wr(pScrn, CRTC_INDEX_COLOR, crtcindex, value);
1006 static Bool init_zm_cr(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1008 /* INIT_ZM_CR opcode: 0x53 ('S')
1010 * offset (8 bit): opcode
1011 * offset + 1 (8 bit): CRTC index
1012 * offset + 2 (8 bit): value
1014 * Assign "value" to CRTC register with index "CRTC index".
1017 uint8_t crtcindex = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 1])));
1018 uint8_t data = bios->data[offset + 2];
1020 if (!iexec->execute)
1023 nv_port_wr(pScrn, CRTC_INDEX_COLOR, crtcindex, data);
1028 static Bool init_zm_cr_group(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1030 /* INIT_ZM_CR opcode: 0x54 ('T')
1032 * offset (8 bit): opcode
1033 * offset + 1 (8 bit): count
1034 * offset + 2 (8 bit): CRTC index 1
1035 * offset + 3 (8 bit): value 1
1038 * For "count", assign "value n" to CRTC register with index "CRTC index n".
1041 uint8_t count = bios->data[offset + 1];
1044 if (!iexec->execute)
1047 for (i = 0; i < count; i++)
1048 init_zm_cr(pScrn, bios, offset + 2 + 2 * i - 1, iexec);
1053 static Bool init_condition_time(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1055 /* My BIOS does not use this command. */
1056 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
1061 static Bool init_zm_reg_sequence(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1063 /* INIT_ZM_REG_SEQUENCE opcode: 0x58 ('X')
1065 * offset (8 bit): opcode
1066 * offset + 1 (32 bit): base register
1067 * offset + 5 (8 bit): count
1068 * offset + 6 (32 bit): value 1
1071 * Starting at offset + 6 there are "count" 32 bit values.
1072 * For "count" iterations set "base register" + 4 * current_iteration
1073 * to "value current_iteration"
1076 uint32_t basereg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 1])));
1077 uint32_t count = bios->data[offset + 5];
1080 if (!iexec->execute)
1083 if (DEBUGLEVEL >= 6)
1084 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1085 "0x%04X: BaseReg: 0x%08X, Count: 0x%02X\n",
1086 offset, basereg, count);
1088 for (i = 0; i < count; i++) {
1089 uint32_t reg = basereg + i * 4;
1091 if ((reg & 0xffc) == 0x3c0)
1092 ErrorF("special case: FIXME\n");
1093 if ((reg & 0xffc) == 0x3cc)
1094 ErrorF("special case: FIXME\n");
1096 uint32_t data = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 6 + i * 4])));
1098 nv32_wr(pScrn, reg, data);
1104 static Bool init_indirect_reg(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1106 /* INIT_INDIRECT_REG opcode: 0x5A
1108 * offset (8 bit): opcode
1109 * offset + 1 (32 bit): register
1110 * offset + 5 (16 bit): adress offset (in bios)
1112 * Lookup value at offset data in the bios and write it to reg
1114 CARD32 reg = *((CARD32 *) (&bios->data[offset + 1]));
1115 CARD16 data = le16_to_cpu(*((CARD16 *) (&bios->data[offset + 5])));
1116 CARD32 data2 = bios->data[data];
1118 if (iexec->execute) {
1119 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1120 "0x%04X: REG: 0x%04X, DATA AT: 0x%04X, VALUE IS: 0x%08X\n",
1121 offset, reg, data, data2);
1123 if (DEBUGLEVEL >= 6) {
1125 nv32_rd(pScrn, reg, &tmpval);
1126 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%08X\n", offset, tmpval);
1129 nv32_wr(pScrn, reg, data2);
1134 static Bool init_sub_direct(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1136 /* INIT_SUB_DIRECT opcode: 0x5B ('[')
1138 * offset (8 bit): opcode
1139 * offset + 1 (16 bit): subroutine offset (in bios)
1141 * Calls a subroutine that will execute commands until INIT_DONE
1145 uint16_t sub_offset = le16_to_cpu(*((uint16_t *) (&bios->data[offset + 1])));
1147 if (!iexec->execute)
1150 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: EXECUTING SUB-ROUTINE AT 0x%04X\n",
1151 offset, sub_offset);
1153 parse_init_table(pScrn, bios, sub_offset, iexec);
1155 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: END OF SUB-ROUTINE AT 0x%04X\n",
1156 offset, sub_offset);
1161 static Bool init_copy_nv_reg(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1163 CARD32 srcreg = *((CARD32 *) (&bios->data[offset + 1]));
1164 CARD8 shift = *((CARD8 *) (&bios->data[offset + 5]));
1165 CARD32 and1 = *((CARD32 *) (&bios->data[offset + 6]));
1166 CARD32 xor = *((CARD32 *) (&bios->data[offset + 10]));
1167 CARD32 dstreg = *((CARD32 *) (&bios->data[offset + 14]));
1168 CARD32 and2 = *((CARD32 *) (&bios->data[offset + 18]));
1172 if (iexec->execute) {
1173 nv32_rd(pScrn, srcreg, &srcdata);
1180 srcdata = (srcdata & and1) ^ xor;
1182 nv32_rd(pScrn, dstreg, &dstdata);
1188 nv32_rd(pScrn, dstreg, &tmp);
1190 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: REG: 0x%08X, VALUE: 0x%08X\n", offset, dstreg,
1193 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%08X\n", offset, tmp);
1195 nv32_wr(pScrn, dstreg, dstdata);
1200 static Bool init_zm_index_io(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1202 /* INIT_ZM_INDEX_IO opcode: 0x62 ('b')
1204 * offset (8 bit): opcode
1205 * offset + 1 (16 bit): CRTC port
1206 * offset + 3 (8 bit): CRTC index
1207 * offset + 4 (8 bit): data
1209 * Write "data" to index "CRTC index" of "CRTC port"
1211 uint16_t crtcport = le16_to_cpu(*((uint16_t *)(&bios->data[offset + 1])));
1212 uint8_t crtcindex = bios->data[offset + 3];
1213 uint8_t data = bios->data[offset + 4];
1215 if (!iexec->execute)
1218 nv_port_wr(pScrn, crtcport, crtcindex, data);
1223 static Bool init_compute_mem(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1225 /* INIT_COMPUTE_MEM opcode: 0x63 ('c')
1227 * offset (8 bit): opcode
1232 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
1234 uint16_t ramcfg = le16_to_cpu(*((uint16_t *)(&bios->data[bios->ram_table_offset])));
1239 if (!iexec->execute)
1242 nv32_rd(pScrn, 0x00101000, &strapinfo);
1243 nv32_rd(pScrn, 0x00100080, &pfb_debug);
1245 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "STRAPINFO: 0x%08X\n", strapinfo);
1246 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PFB_DEBUG: 0x%08X\n", pfb_debug);
1247 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RAM CFG: 0x%04X\n", ramcfg);
1249 pfb_debug &= 0xffffffef;
1251 strapinfo &= 0x0000000f;
1252 ramcfg2 = le16_to_cpu(*((uint16_t *)
1253 (&bios->data[bios->ram_table_offset + (2 * strapinfo)])));
1255 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "AFTER MANIPULATION\n");
1256 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "STRAPINFO: 0x%08X\n", strapinfo);
1257 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PFB_DEBUG: 0x%08X\n", pfb_debug);
1258 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RAM CFG2: 0x%08X\n", ramcfg2);
1264 nv32_rd(pScrn, 0x00100200, ®1);
1265 nv32_rd(pScrn, 0x0010020C, ®2);
1267 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x00100200: 0x%08X\n", reg1);
1268 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x0010020C: 0x%08X\n", reg2);
1274 static Bool init_reset(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1276 /* INIT_RESET opcode: 0x65 ('e')
1278 * offset (8 bit): opcode
1279 * offset + 1 (32 bit): register
1280 * offset + 5 (32 bit): value1
1281 * offset + 9 (32 bit): value2
1283 * Assign "value1" to "register", then assign "value2" to "register"
1286 uint32_t reg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 1])));
1287 uint32_t value1 = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 5])));
1288 uint32_t value2 = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 9])));
1291 if (!iexec->execute)
1294 if (DEBUGLEVEL >= 6)
1295 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1296 "0x%04X: Reg: 0x%08X, Value1: 0x%08X, Value2: 0x%08X\n",
1297 offset, reg, value1, value2);
1299 /* 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 */
1300 nv32_rd(pScrn, NV_PBUS_PCI_NV_19, &pci_nv_19);
1302 nv32_rd(pScrn, PCICFG(PCICFG_ROMSHADOW), &tmpval);
1303 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: PCICFG_ROMSHADOW: 0x%02X\n", offset, tmpval);
1305 nv32_wr(pScrn, NV_PBUS_PCI_NV_19, 0);
1306 nv32_wr(pScrn, reg, value1);
1307 nv32_wr(pScrn, reg, value2);
1308 nv32_wr(pScrn, NV_PBUS_PCI_NV_19, pci_nv_19);
1310 /* PCI Config space init needs to be added here. */
1311 /* if (nv32_rd(pScrn, PCICFG(PCICFG_ROMSHADOW), value1)) */
1312 /* nv32_wr(pScrn, PCICFG(PCICFG_ROMSHADOW), value1 & 0xfffffffe) */
1317 static Bool init_index_io8(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1319 /* INIT_INDEX_IO8 opcode: 0x69
1321 * offset (8 bit): opcode
1322 * offset + 1 (16 bit): CRTC reg
1323 * offset + 3 (8 bit): and mask
1324 * offset + 4 (8 bit): or with
1329 NVPtr pNv = NVPTR(pScrn);
1330 volatile CARD8 *ptr = crtchead ? pNv->PCIO1 : pNv->PCIO0;
1331 CARD16 reg = le16_to_cpu(*((CARD16 *)(&bios->data[offset + 1])));
1332 CARD8 and = *((CARD8 *)(&bios->data[offset + 3]));
1333 CARD8 or = *((CARD8 *)(&bios->data[offset + 4]));
1336 if (iexec->execute) {
1337 data = (VGA_RD08(ptr, reg) & and) | or;
1339 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1340 "0x%04X: CRTC REG: 0x%04X, VALUE: 0x%02X\n",
1342 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%02X\n", offset,
1343 VGA_RD08(ptr, reg));
1345 #ifdef PERFORM_WRITE
1346 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "init_index_io8 crtcreg 0x%X value 0x%X\n",reg,data);
1348 VGA_WR08(ptr, reg, data);
1354 static Bool init_sub(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1356 /* INIT_SUB opcode: 0x6B ('k')
1358 * offset (8 bit): opcode
1359 * offset + 1 (8 bit): script number
1361 * Execute script number "script number", as a subroutine
1364 uint8_t sub = bios->data[offset + 1];
1366 if (!iexec->execute)
1369 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1370 "0x%04X: EXECUTING SUB-SCRIPT %d\n", offset, sub);
1372 parse_init_table(pScrn, bios,
1373 le16_to_cpu(*((CARD16 *)(&bios->data[bios->init_script_tbls_ptr + sub * 2]))),
1376 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1377 "0x%04X: END OF SUB-SCRIPT %d\n", offset, sub);
1382 static Bool init_ram_condition(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1384 /* INIT_RAM_CONDITION opcode: 0x6D
1386 * offset (8 bit): opcode
1387 * offset + 1 (8 bit): and mask
1388 * offset + 2 (8 bit): cmpval
1390 * Test if (NV_PFB_BOOT & and mask) matches cmpval
1392 NVPtr pNv = NVPTR(pScrn);
1393 CARD8 and = *((CARD8 *) (&bios->data[offset + 1]));
1394 CARD8 cmpval = *((CARD8 *) (&bios->data[offset + 2]));
1397 if (iexec->execute) {
1398 data=(pNv->PFB[NV_PFB_BOOT/4])∧
1400 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1401 "0x%04X: CHECKING IF REGVAL: 0x%08X equals COND: 0x%08X\n",
1402 offset, data, cmpval);
1404 if (data == cmpval) {
1405 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1406 "0x%04X: CONDITION FULFILLED - CONTINUING TO EXECUTE\n",
1409 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CONDITION IS NOT FULFILLED.\n", offset);
1410 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1411 "0x%04X: ------ SKIPPING FOLLOWING COMMANDS ------\n", offset);
1412 iexec->execute = FALSE;
1418 static Bool init_nv_reg(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1420 /* INIT_NV_REG opcode: 0x6E ('n')
1422 * offset (8 bit): opcode
1423 * offset + 1 (32 bit): register
1424 * offset + 5 (32 bit): mask
1425 * offset + 9 (32 bit): data
1427 * Assign ((REGVAL("register") & "mask") | "data") to "register"
1430 uint32_t reg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 1])));
1431 uint32_t mask = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 5])));
1432 uint32_t data = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 9])));
1435 if (!iexec->execute)
1438 if (DEBUGLEVEL >= 6)
1439 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1440 "0x%04X: Reg: 0x%08X, Mask: 0x%08X, Data: 0x%08X\n",
1441 offset, reg, mask, data);
1443 nv32_rd(pScrn, reg, &value);
1445 value = (value & mask) | data;
1447 nv32_wr(pScrn, reg, value);
1452 static Bool init_macro(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1454 /* INIT_MACRO opcode: 0x6F ('o')
1456 * offset (8 bit): opcode
1457 * offset + 1 (8 bit): macro number
1459 * Look up macro index "macro number" in the macro index table.
1460 * The macro index table entry has 1 byte for the index in the macro table,
1461 * and 1 byte for the number of times to repeat the macro.
1462 * The macro table entry has 4 bytes for the register address and
1463 * 4 bytes for the value to write to that register
1466 uint8_t macro_index_tbl_idx = bios->data[offset + 1];
1467 uint16_t tmp = bios->macro_index_tbl_ptr + (macro_index_tbl_idx * MACRO_INDEX_SIZE);
1468 uint8_t macro_tbl_idx = bios->data[tmp];
1469 uint8_t count = bios->data[tmp + 1];
1473 if (!iexec->execute)
1476 if (DEBUGLEVEL >= 6)
1477 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1478 "0x%04X: Macro: 0x%02X, MacroTableIndex: 0x%02X, Count: 0x%02X\n",
1479 offset, macro_index_tbl_idx, macro_tbl_idx, count);
1481 for (i = 0; i < count; i++) {
1482 uint16_t macroentryptr = bios->macro_tbl_ptr + (macro_tbl_idx + i) * MACRO_SIZE;
1484 reg = le32_to_cpu(*((uint32_t *)(&bios->data[macroentryptr])));
1485 data = le32_to_cpu(*((uint32_t *)(&bios->data[macroentryptr + 4])));
1487 nv32_wr(pScrn, reg, data);
1493 static Bool init_done(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1495 /* INIT_DONE opcode: 0x71 ('q')
1497 * offset (8 bit): opcode
1499 * End the current script
1502 /* mild retval abuse to stop parsing this table */
1506 static Bool init_resume(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1508 /* INIT_RESUME opcode: 0x72 ('r')
1510 * offset (8 bit): opcode
1512 * End the current execute / no-execute condition
1518 iexec->execute = TRUE;;
1519 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1520 "0x%04X: ---- EXECUTING FOLLOWING COMMANDS ----\n", offset);
1525 static Bool init_ram_condition2(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1527 /* INIT_RAM_CONDITION2 opcode: 0x73
1529 * offset (8 bit): opcode
1530 * offset + 1 (8 bit): and mask
1531 * offset + 2 (8 bit): cmpval
1533 * Test if (NV_EXTDEV_BOOT & and mask) matches cmpval
1535 NVPtr pNv = NVPTR(pScrn);
1536 CARD32 and = *((CARD32 *) (&bios->data[offset + 1]));
1537 CARD32 cmpval = *((CARD32 *) (&bios->data[offset + 5]));
1540 if (iexec->execute) {
1541 data=(nvReadEXTDEV(pNv, NV_PEXTDEV_BOOT))∧
1543 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1544 "0x%04X: CHECKING IF REGVAL: 0x%08X equals COND: 0x%08X\n",
1545 offset, data, cmpval);
1547 if (data == cmpval) {
1548 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1549 "0x%04X: CONDITION FULFILLED - CONTINUING TO EXECUTE\n",
1552 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CONDITION IS NOT FULFILLED.\n", offset);
1553 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1554 "0x%04X: ------ SKIPPING FOLLOWING COMMANDS ------\n", offset);
1555 iexec->execute = FALSE;
1561 static Bool init_time(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1563 /* INIT_TIME opcode: 0x74 ('t')
1565 * offset (8 bit): opcode
1566 * offset + 1 (16 bit): time
1568 * Sleep for "time" microseconds.
1571 uint16_t time = le16_to_cpu(*((uint16_t *)(&bios->data[offset + 1])));
1573 if (!iexec->execute)
1576 if (DEBUGLEVEL >= 6)
1577 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1578 "0x%04X: Sleeping for 0x%04X microseconds.\n", offset, time);
1585 static Bool init_condition(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1587 /* INIT_CONDITION opcode: 0x75 ('u')
1589 * offset (8 bit): opcode
1590 * offset + 1 (8 bit): condition number
1592 * Check condition "condition number" in the condition table.
1593 * The condition table entry has 4 bytes for the address of the
1594 * register to check, 4 bytes for a mask and 4 for a test value.
1595 * If condition not met skip subsequent opcodes until condition
1596 * is inverted (INIT_NOT), or we hit INIT_RESUME
1599 uint8_t cond = bios->data[offset + 1];
1600 uint16_t condptr = bios->condition_tbl_ptr + cond * CONDITION_SIZE;
1601 uint32_t reg = le32_to_cpu(*((uint32_t *)(&bios->data[condptr])));
1602 uint32_t mask = le32_to_cpu(*((uint32_t *)(&bios->data[condptr + 4])));
1603 uint32_t cmpval = le32_to_cpu(*((uint32_t *)(&bios->data[condptr + 8])));
1606 if (!iexec->execute)
1609 if (DEBUGLEVEL >= 6)
1610 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1611 "0x%04X: Cond: 0x%02X, Reg: 0x%08X, Mask: 0x%08X, Cmpval: 0x%08X\n",
1612 offset, cond, reg, mask, cmpval);
1614 nv32_rd(pScrn, reg, &data);
1617 if (DEBUGLEVEL >= 6)
1618 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1619 "0x%04X: Checking if 0x%08X equals 0x%08X\n",
1620 offset, data, cmpval);
1622 if (data == cmpval) {
1623 if (DEBUGLEVEL >= 6)
1624 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1625 "0x%04X: CONDITION FULFILLED - CONTINUING TO EXECUTE\n", offset);
1627 if (DEBUGLEVEL >= 6)
1628 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1629 "0x%04X: CONDITION IS NOT FULFILLED.\n", offset);
1630 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1631 "0x%04X: ------ SKIPPING FOLLOWING COMMANDS ------\n", offset);
1632 iexec->execute = FALSE;
1638 static Bool init_index_io(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1640 /* INIT_INDEX_IO opcode: 0x78 ('x')
1642 * offset (8 bit): opcode
1643 * offset + 1 (16 bit): CRTC port
1644 * offset + 3 (8 bit): CRTC index
1645 * offset + 4 (8 bit): mask
1646 * offset + 5 (8 bit): data
1648 * Read value at index "CRTC index" on "CRTC port", AND with "mask", OR with "data", write-back
1651 uint16_t crtcport = le16_to_cpu(*((uint16_t *)(&bios->data[offset + 1])));
1652 uint8_t crtcindex = bios->data[offset + 3];
1653 uint8_t mask = bios->data[offset + 4];
1654 uint8_t data = bios->data[offset + 5];
1657 if (!iexec->execute)
1660 if (DEBUGLEVEL >= 6)
1661 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1662 "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, Data: 0x%02X\n",
1663 offset, crtcport, crtcindex, mask, data);
1665 nv_port_rd(pScrn, crtcport, crtcindex, &value);
1666 value = (value & mask) | data;
1667 nv_port_wr(pScrn, crtcport, crtcindex, value);
1672 static Bool init_pll(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1674 /* INIT_PLL opcode: 0x79 ('y')
1676 * offset (8 bit): opcode
1677 * offset + 1 (32 bit): register
1678 * offset + 5 (16 bit): freq
1680 * Set PLL register "register" to coefficients for frequency (10kHz) "freq"
1683 uint32_t reg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 1])));
1684 uint16_t freq = le16_to_cpu(*((uint16_t *)(&bios->data[offset + 5])));
1686 if (!iexec->execute)
1689 if (DEBUGLEVEL >= 6)
1690 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1691 "0x%04X: Reg: 0x%04X, Freq: %d0kHz\n",
1694 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
1699 configval = 0x00011F05;
1706 static Bool init_zm_reg(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1708 /* INIT_ZM_REG opcode: 0x7A ('z')
1710 * offset (8 bit): opcode
1711 * offset + 1 (32 bit): register
1712 * offset + 5 (32 bit): value
1714 * Assign "value" to "register"
1717 uint32_t reg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 1])));
1718 uint32_t value = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 5])));
1720 if (!iexec->execute)
1723 nv32_wr(pScrn, reg, value);
1728 static init_tbl_entry_t itbl_entry[] = {
1729 /* command name , id , length , offset , mult , command handler */
1730 // { "INIT_PROG" , 0x31, 15 , 10 , 4 , init_prog },
1731 { "INIT_IO_RESTRICT_PROG" , 0x32, 11 , 6 , 4 , init_io_restrict_prog },
1732 { "INIT_REPEAT" , 0x33, 2 , 0 , 0 , init_repeat },
1733 { "INIT_IO_RESTRICT_PLL" , 0x34, 12 , 7 , 2 , init_io_restrict_pll },
1734 { "INIT_END_REPEAT" , 0x36, 1 , 0 , 0 , init_end_repeat },
1735 { "INIT_COPY" , 0x37, 11 , 0 , 0 , init_copy },
1736 { "INIT_NOT" , 0x38, 1 , 0 , 0 , init_not },
1737 { "INIT_IO_FLAG_CONDITION" , 0x39, 2 , 0 , 0 , init_io_flag_condition },
1738 { "INIT_INDEX_ADDRESS_LATCHED" , 0x49, 18 , 17 , 2 , init_idx_addr_latched },
1739 { "INIT_IO_RESTRICT_PLL2" , 0x4A, 11 , 6 , 4 , init_io_restrict_pll2 },
1740 { "INIT_PLL2" , 0x4B, 9 , 0 , 0 , init_pll2 },
1741 /* { "INIT_I2C_BYTE" , 0x4C, x , x , x , init_i2c_byte }, */
1742 /* { "INIT_ZM_I2C_BYTE" , 0x4D, x , x , x , init_zm_i2c_byte }, */
1743 /* { "INIT_ZM_I2C" , 0x4E, x , x , x , init_zm_i2c }, */
1744 { "INIT_50" , 0x50, 3 , 2 , 2 , init_50 },
1745 { "INIT_CR_INDEX_ADDRESS_LATCHED" , 0x51, 5 , 4 , 1 , init_cr_idx_adr_latch },
1746 { "INIT_CR" , 0x52, 4 , 0 , 0 , init_cr },
1747 { "INIT_ZM_CR" , 0x53, 3 , 0 , 0 , init_zm_cr },
1748 { "INIT_ZM_CR_GROUP" , 0x54, 2 , 1 , 2 , init_zm_cr_group },
1749 // { "INIT_CONDITION_TIME" , 0x56, 3 , 0 , 0 , init_condition_time },
1750 { "INIT_ZM_REG_SEQUENCE" , 0x58, 6 , 5 , 4 , init_zm_reg_sequence },
1751 // { "INIT_INDIRECT_REG" , 0x5A, 7 , 0 , 0 , init_indirect_reg },
1752 { "INIT_SUB_DIRECT" , 0x5B, 3 , 0 , 0 , init_sub_direct },
1753 // { "INIT_COPY_NV_REG" , 0x5F, 22 , 0 , 0 , init_copy_nv_reg },
1754 { "INIT_ZM_INDEX_IO" , 0x62, 5 , 0 , 0 , init_zm_index_io },
1755 { "INIT_COMPUTE_MEM" , 0x63, 1 , 0 , 0 , init_compute_mem },
1756 { "INIT_RESET" , 0x65, 13 , 0 , 0 , init_reset },
1757 /* { "INIT_NEXT" , 0x66, x , x , x , init_next }, */
1758 /* { "INIT_NEXT" , 0x67, x , x , x , init_next }, */
1759 /* { "INIT_NEXT" , 0x68, x , x , x , init_next }, */
1760 // { "INIT_INDEX_IO8" , 0x69, 5 , 0 , 0 , init_index_io8 },
1761 { "INIT_SUB" , 0x6B, 2 , 0 , 0 , init_sub },
1762 // { "INIT_RAM_CONDITION" , 0x6D, 3 , 0 , 0 , init_ram_condition },
1763 { "INIT_NV_REG" , 0x6E, 13 , 0 , 0 , init_nv_reg },
1764 { "INIT_MACRO" , 0x6F, 2 , 0 , 0 , init_macro },
1765 { "INIT_DONE" , 0x71, 1 , 0 , 0 , init_done },
1766 { "INIT_RESUME" , 0x72, 1 , 0 , 0 , init_resume },
1767 // { "INIT_RAM_CONDITION2" , 0x73, 9 , 0 , 0 , init_ram_condition2 },
1768 { "INIT_TIME" , 0x74, 3 , 0 , 0 , init_time },
1769 { "INIT_CONDITION" , 0x75, 2 , 0 , 0 , init_condition },
1770 /* { "INIT_IO_CONDITION" , 0x76, x , x , x , init_io_condition }, */
1771 { "INIT_INDEX_IO" , 0x78, 6 , 0 , 0 , init_index_io },
1772 { "INIT_PLL" , 0x79, 7 , 0 , 0 , init_pll },
1773 { "INIT_ZM_REG" , 0x7A, 9 , 0 , 0 , init_zm_reg },
1774 /* { "INIT_RAM_RESTRICT_ZM_REG_GROUP" , 0x8F, x , x , x , init_ram_restrict_zm_reg_group }, */
1775 /* { "INIT_COPY_ZM_REG" , 0x90, x , x , x , init_copy_zm_reg }, */
1776 /* { "INIT_ZM_REG_GROUP_ADDRESS_LATCHED" , 0x91, x , x , x , init_zm_reg_group_addr_latched }, */
1777 /* { "INIT_RESERVED" , 0x92, x , x , x , init_reserved }, */
1778 { 0 , 0 , 0 , 0 , 0 , 0 }
1781 static unsigned int get_init_table_entry_length(bios_t *bios, unsigned int offset, int i)
1783 /* Calculates the length of a given init table entry. */
1784 return itbl_entry[i].length + bios->data[offset + itbl_entry[i].length_offset]*itbl_entry[i].length_multiplier;
1787 static void parse_init_table(ScrnInfoPtr pScrn, bios_t *bios, unsigned int offset, init_exec_t *iexec)
1789 /* Parses all commands in a init table. */
1791 /* We start out executing all commands found in the
1792 * init table. Some op codes may change the status
1793 * of this variable to SKIP, which will cause
1794 * the following op codes to perform no operation until
1795 * the value is changed back to EXECUTE.
1801 /* Loop until INIT_DONE causes us to break out of the loop
1802 * (or until offset > bios length just in case... )
1803 * (and no more than 10000 iterations just in case... ) */
1804 while ((offset < bios->length) && (count++ < 10000)) {
1805 id = bios->data[offset];
1807 /* Find matching id in itbl_entry */
1808 for (i = 0; itbl_entry[i].name && (itbl_entry[i].id != id); i++)
1811 if (itbl_entry[i].name) {
1812 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ (0x%02X) - %s ]\n",
1813 offset, itbl_entry[i].id, itbl_entry[i].name);
1815 /* execute eventual command handler */
1816 if (itbl_entry[i].handler)
1817 if (!(*itbl_entry[i].handler)(pScrn, bios, offset, iexec))
1820 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1821 "0x%04X: Init table command not found: 0x%02X\n", offset, id);
1825 /* Add the offset of the current command including all data
1826 * of that command. The offset will then be pointing on the
1829 offset += get_init_table_entry_length(bios, offset, i);
1833 void parse_init_tables(ScrnInfoPtr pScrn, bios_t *bios)
1835 /* Loops and calls parse_init_table() for each present table. */
1839 init_exec_t iexec = {TRUE, FALSE};
1841 while ((table = le16_to_cpu(*((uint16_t *)(&bios->data[bios->init_script_tbls_ptr + i]))))) {
1843 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: Parsing init table %d\n",
1846 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1847 "0x%04X: ------ EXECUTING FOLLOWING COMMANDS ------\n", table);
1849 parse_init_table(pScrn, bios, table, &iexec);
1855 uint16_t fptablepointer;
1856 uint16_t fpxlatetableptr;
1857 uint16_t lvdsmanufacturerpointer;
1858 uint16_t fpxlatemanufacturertableptr;
1861 static void link_head_and_output(ScrnInfoPtr pScrn, int head, int dcb_entry)
1863 /* The BIOS scripts don't do this for us, sadly */
1864 /* Luckily we do know the values ;-) */
1866 NVPtr pNv = NVPTR(pScrn);
1867 int preferred_output = (ffs(pNv->dcb_table.entry[dcb_entry].or) & OUTPUT_1) >> 1;
1868 uint8_t tmds04 = 0x80;
1869 uint32_t tmds_ctrl, tmds_ctrl2;
1871 /* Bit 3 crosswires output and crtc */
1872 if (head != preferred_output)
1875 if (pNv->dcb_table.entry[dcb_entry].type == OUTPUT_LVDS)
1878 tmds_ctrl = NV_PRAMDAC0_OFFSET + (preferred_output ? NV_PRAMDAC0_SIZE : 0) + NV_RAMDAC_FP_TMDS_CONTROL;
1879 tmds_ctrl2 = NV_PRAMDAC0_OFFSET + (preferred_output ? NV_PRAMDAC0_SIZE : 0) + NV_RAMDAC_FP_TMDS_CONTROL_2;
1881 Bool oldexecute = pNv->VBIOS.execute;
1882 pNv->VBIOS.execute = TRUE;
1883 nv32_wr(pScrn, tmds_ctrl + 4, tmds04);
1884 nv32_wr(pScrn, tmds_ctrl, 0x04);
1885 nv32_wr(pScrn, tmds_ctrl2 + 4, tmds04 ^ 0x08);
1886 nv32_wr(pScrn, tmds_ctrl2, 0x04);
1887 pNv->VBIOS.execute = oldexecute;
1890 void call_lvds_script(ScrnInfoPtr pScrn, int head, int dcb_entry, enum LVDS_script script)
1892 NVPtr pNv = NVPTR(pScrn);
1893 bios_t *bios = &pNv->VBIOS;
1894 init_exec_t iexec = {TRUE, FALSE};
1896 uint8_t sub = bios->data[bios->fp.script_table + script];
1897 uint16_t scriptofs = le16_to_cpu(*((CARD16 *)(&bios->data[bios->init_script_tbls_ptr + sub * 2])));
1898 if (!sub || !scriptofs)
1901 if (script == LVDS_PANEL_ON && bios->fp.reset_after_pclk_change)
1902 call_lvds_script(pScrn, head, dcb_entry, LVDS_RESET);
1903 if (script == LVDS_RESET && bios->fp.power_off_for_reset)
1904 call_lvds_script(pScrn, head, dcb_entry, LVDS_PANEL_OFF);
1906 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Calling LVDS script %d:\n", script);
1907 pNv->VBIOS.execute = TRUE;
1908 nv_port_wr(pScrn, CRTC_INDEX_COLOR, NV_VGA_CRTCX_OWNER,
1909 head ? NV_VGA_CRTCX_OWNER_HEADB : NV_VGA_CRTCX_OWNER_HEADA);
1910 parse_init_table(pScrn, bios, scriptofs, &iexec);
1911 pNv->VBIOS.execute = FALSE;
1913 if (script == LVDS_PANEL_OFF)
1914 usleep(bios->fp.off_on_delay * 1000);
1915 if (script == LVDS_RESET)
1916 link_head_and_output(pScrn, head, dcb_entry);
1919 static void parse_fp_mode_table(ScrnInfoPtr pScrn, bios_t *bios, struct fppointers *fpp)
1921 NVPtr pNv = NVPTR(pScrn);
1922 unsigned int fpstrapping;
1923 uint8_t *fptable, *fpxlatetable;
1925 uint8_t fptable_ver, headerlen = 0, recordlen = 44;
1927 DisplayModePtr mode;
1929 fpstrapping = (nvReadEXTDEV(pNv, NV_PEXTDEV_BOOT) >> 16) & 0xf;
1931 if (fpp->fptablepointer == 0x0) {
1932 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1933 "Pointer to flat panel table invalid\n");
1937 fptable = &bios->data[fpp->fptablepointer];
1939 fptable_ver = fptable[0];
1941 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1942 "Found flat panel mode table revision %d.%d\n",
1943 fptable_ver >> 4, fptable_ver & 0xf);
1945 switch (fptable_ver) {
1946 /* PINS version 0x5.0x11 BIOSen have version 1 like tables, but no version field,
1947 * and miss one of the spread spectrum/PWM bytes.
1948 * This could affect early GF2Go parts (not seen any appropriate ROMs though).
1949 * Here we assume that a version of 0x05 matches this case (combining with a
1950 * PINS version check would be better), as the common case for the panel type
1951 * field is 0x0005, and that is in fact what we are reading the first byte of. */
1952 case 0x05: /* some NV10, 11, 15, 16 */
1956 case 0x10: /* some NV15/16, and NV11+ */
1959 fpxlatetable = &bios->data[fpp->fpxlatetableptr];
1960 fpindex = fpxlatetable[fpstrapping];
1961 if (fpindex > 0xf) {
1962 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1963 "Bad flat panel table index\n");
1967 case 0x20: /* NV40+ */
1968 headerlen = fptable[1];
1969 recordlen = fptable[2]; // check this, or hardcode as 0x20
1970 /* may be the wrong test, if there's a translation table
1971 if (fpstrapping > fptable[3]) {
1972 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1973 "Flat panel strapping number too high\n");
1977 /* I don't know where the index for the table comes from in v2.0, so bail
1980 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1981 "FP Table revision not currently supported\n");
1985 if (!(mode = xcalloc(1, sizeof(DisplayModeRec))))
1988 int modeofs = headerlen + recordlen * fpindex + ofs;
1989 mode->Clock = le16_to_cpu(*(uint16_t *)&fptable[modeofs]) * 10;
1990 mode->HDisplay = le16_to_cpu(*(uint16_t *)&fptable[modeofs + 2]);
1991 mode->HSyncStart = le16_to_cpu(*(uint16_t *)&fptable[modeofs + 10] + 1);
1992 mode->HSyncEnd = le16_to_cpu(*(uint16_t *)&fptable[modeofs + 12] + 1);
1993 mode->HTotal = le16_to_cpu(*(uint16_t *)&fptable[modeofs + 14] + 1);
1994 mode->VDisplay = le16_to_cpu(*(uint16_t *)&fptable[modeofs + 16]);
1995 mode->VSyncStart = le16_to_cpu(*(uint16_t *)&fptable[modeofs + 24] + 1);
1996 mode->VSyncEnd = le16_to_cpu(*(uint16_t *)&fptable[modeofs + 26] + 1);
1997 mode->VTotal = le16_to_cpu(*(uint16_t *)&fptable[modeofs + 28] + 1);
1998 mode->Flags |= (fptable[modeofs + 30] & 0x10) ? V_PHSYNC : V_NHSYNC;
1999 mode->Flags |= (fptable[modeofs + 30] & 0x1) ? V_PVSYNC : V_NVSYNC;
2002 * bytes 1-2 are "panel type", including bits on whether Colour/mono, single/dual link, and type (TFT etc.)
2003 * bytes 3-6 are bits per colour in RGBX
2005 * 13-14 is HValid Start
2006 * 15-16 is HValid End
2007 * bytes 38-39 relate to spread spectrum settings
2008 * bytes 40-43 are something to do with PWM */
2010 mode->prev = mode->next = NULL;
2011 mode->status = MODE_OK;
2012 mode->type = M_T_DRIVER | M_T_PREFERRED;
2013 xf86SetModeDefaultName(mode);
2015 // if (pNv->debug_modes) { this should exist
2016 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2017 "Found flat panel mode in BIOS tables:\n");
2018 xf86PrintModeline(pScrn->scrnIndex, mode);
2021 bios->fp.native_mode = mode;
2024 static void parse_lvds_manufacturer_table(ScrnInfoPtr pScrn, bios_t *bios, struct fppointers *fpp)
2026 NVPtr pNv = NVPTR(pScrn);
2027 unsigned int fpstrapping;
2028 uint8_t *lvdsmanufacturertable, *fpxlatemanufacturertable;
2029 int lvdsmanufacturerindex = 0;
2030 uint8_t lvds_ver, headerlen, recordlen;
2032 fpstrapping = (nvReadEXTDEV(pNv, NV_PEXTDEV_BOOT) >> 16) & 0xf;
2034 if (fpp->lvdsmanufacturerpointer == 0x0) {
2035 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2036 "Pointer to LVDS manufacturer table invalid\n");
2040 lvdsmanufacturertable = &bios->data[fpp->lvdsmanufacturerpointer];
2041 lvds_ver = lvdsmanufacturertable[0];
2043 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2044 "Found LVDS manufacturer table revision %d\n",
2048 case 0x0a: /* pre NV40 */
2049 fpxlatemanufacturertable = &bios->data[fpp->fpxlatemanufacturertableptr];
2050 lvdsmanufacturerindex = fpxlatemanufacturertable[fpstrapping];
2053 recordlen = lvdsmanufacturertable[1];
2056 // case 0x: /* NV40+ */
2058 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2059 "LVDS manufacturer table revision not currently supported\n");
2063 uint16_t lvdsofs = bios->fp.script_table = fpp->lvdsmanufacturerpointer + headerlen + recordlen * lvdsmanufacturerindex;
2064 bios->fp.power_off_for_reset = bios->data[lvdsofs] & 1;
2065 bios->fp.reset_after_pclk_change = bios->data[lvdsofs] & 2;
2066 bios->fp.dual_link = bios->data[lvdsofs] & 4;
2067 bios->fp.if_is_24bit = bios->data[lvdsofs] & 16;
2068 bios->fp.off_on_delay = le16_to_cpu(*(uint16_t *)&bios->data[lvdsofs + 7]);
2071 void parse_t_table(ScrnInfoPtr pScrn, bios_t *bios, uint8_t dcb_entry, uint8_t head, uint16_t pxclk)
2073 /* the dcb_entry parameter is the index of the appropriate DCB entry
2074 * the pxclk parameter is in 10s of kHz (eg. 108Mhz is 10800, or 0x2a30)
2076 * This runs the TMDS regs setting code found on BIT bios cards
2078 * The table here is typically found just before the DCB table, with a
2079 * characteristic signature of 0x11,0x13 (1.1 being version, 0x13 being
2082 * At offset +7 is a pointer to a script, which I don't know how to run yet
2083 * At offset +9 is a pointer to another script, likewise
2084 * Offset +11 has a pointer to a table where the first word is a pxclk
2085 * frequency and the second word a pointer to a script, which should be
2086 * run if the comparison pxclk frequency is less than the pxclk desired.
2087 * This repeats for decreasing comparison frequencies
2088 * Offset +13 has a pointer to a similar table
2089 * The selection of table (and possibly +7/+9 script) is dictated by
2090 * "or" from the DCB.
2091 * For unffs(ffs(or)) == 0, use the first table, for
2092 * unffs(ffs(or)) == 4, use the second.
2093 * unffs(ffs(or)) == 2 does not seem to occur for TMDS.
2095 NVPtr pNv = NVPTR(pScrn);
2096 uint16_t ttableptr, script1, script2, clktable, tscript = 0;
2098 uint16_t compareclk;
2099 init_exec_t iexec = {TRUE, FALSE};
2101 if (pNv->dcb_table.entry[dcb_entry].location) /* off chip */
2104 ttableptr = bios->t_table_ptr;
2106 if (ttableptr == 0x0) {
2107 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Pointer to T table invalid\n");
2111 Bool execute_backup = bios->execute;
2112 /* This table has to be excecuted */
2113 bios->execute = TRUE;
2115 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Found T table revision %d.%d\n",
2116 bios->data[ttableptr] >> 4, bios->data[ttableptr] & 0xf);
2118 script1 = le16_to_cpu(*((uint16_t *)&bios->data[ttableptr + 7]));
2119 script2 = le16_to_cpu(*((uint16_t *)&bios->data[ttableptr + 9]));
2121 if (bios->data[script1] != 'q' || bios->data[script2] != 'q') {
2122 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "T table script pointers not stubbed\n");
2126 switch ((ffs(pNv->dcb_table.entry[dcb_entry].or) - 1) * 2) {
2128 clktable = le16_to_cpu(*((uint16_t *)&bios->data[ttableptr + 11]));
2131 clktable = le16_to_cpu(*((uint16_t *)&bios->data[ttableptr + 13]));
2134 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "(ffs(or) - 1) * 2 was not 0 or 4\n");
2139 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Pixel clock comparison table not found\n");
2144 compareclk = le16_to_cpu(*((uint16_t *)&bios->data[clktable + 4 * i]));
2145 if (pxclk >= compareclk) {
2146 tscript = le16_to_cpu(*((uint16_t *)&bios->data[clktable + 2 + 4 * i]));
2150 } while (compareclk);
2153 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "T script not found\n");
2157 /* We must set the owner register appropriately */
2158 nv_port_wr(pScrn, CRTC_INDEX_COLOR, NV_VGA_CRTCX_OWNER, head * 3);
2160 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: Parsing T table\n", tscript);
2161 nv_port_wr(pScrn, CRTC_INDEX_COLOR, 0x57, 0);
2162 nv_port_wr(pScrn, CRTC_INDEX_COLOR, 0x58, dcb_entry);
2163 parse_init_table(pScrn, bios, tscript, &iexec);
2164 /* restore previous state */
2165 bios->execute = execute_backup;
2167 link_head_and_output(pScrn, head, dcb_entry);
2170 static int parse_bit_display_tbl_entry(ScrnInfoPtr pScrn, bios_t *bios, bit_entry_t *bitentry)
2173 /* Parses the flat panel table segment that the bit entry points to.
2174 * Starting at bitentry->offset:
2176 * offset + 0 (16 bits): FIXME table pointer
2177 * offset + 2 (16 bits): mode table pointer
2180 struct fppointers fpp;
2182 /* If it's not a laptop, you probably don't care about fptables */
2183 /* FIXME: detect mobile BIOS? */
2185 NVPtr pNv = NVPTR(pScrn);
2190 if (bitentry->length != 4) {
2191 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2192 "Do not understand BIT display table entry.\n");
2196 table = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset])));
2197 fpp.fptablepointer = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 2])));
2199 parse_fp_mode_table(pScrn, bios, &fpp);
2204 static unsigned int parse_bit_init_tbl_entry(ScrnInfoPtr pScrn, bios_t *bios, bit_entry_t *bitentry)
2206 /* Parses the init table segment that the bit entry points to.
2207 * Starting at bitentry->offset:
2209 * offset + 0 (16 bits): init script tables pointer
2210 * offset + 2 (16 bits): macro index table pointer
2211 * offset + 4 (16 bits): macro table pointer
2212 * offset + 6 (16 bits): condition table pointer
2213 * offset + 8 (16 bits): io condition table pointer
2214 * offset + 10 (16 bits): io flag condition table pointer
2215 * offset + 12 (16 bits): init function table pointer
2218 * * Are 'I' bit entries always of length 0xE?
2222 if (bitentry->length < 12) {
2223 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2224 "Unable to recognize BIT init table entry.\n");
2228 bios->init_script_tbls_ptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset])));
2229 bios->macro_index_tbl_ptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 2])));
2230 bios->macro_tbl_ptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 4])));
2231 bios->condition_tbl_ptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 6])));
2232 bios->io_condition_tbl_ptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 8])));
2233 bios->io_flag_condition_tbl_ptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 10])));
2234 bios->init_function_tbl_ptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 12])));
2236 parse_init_tables(pScrn, bios);
2241 static int parse_bit_t_tbl_entry(ScrnInfoPtr pScrn, bios_t *bios, bit_entry_t *bitentry)
2243 /* Parses the pointer to the T table
2245 * Starting at bitentry->offset:
2247 * offset + 0 (16 bits): T table pointer
2250 if (bitentry->length != 2) {
2251 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2252 "Do not understand BIT T table entry.\n");
2256 bios->t_table_ptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset])));
2258 /* FIXME just for testing */
2259 // parse_t_table(pScrn, bios, 0, 0x2a30);
2264 static unsigned int parse_bmp_table_pointers(ScrnInfoPtr pScrn, bios_t *bios, bit_entry_t *bitentry)
2266 /* Parse the pointers for useful tables in the BMP structure, starting at
2267 * offset 75 from the ..NV. signature.
2269 * First 7 pointers as for parse_bit_init_tbl_entry
2271 * offset + 30: flat panel timings table pointer
2272 * offset + 32: flat panel strapping translation table pointer
2273 * offset + 42: LVDS manufacturer panel config table pointer
2274 * offset + 44: LVDS manufacturer strapping translation table pointer
2277 NVPtr pNv = NVPTR(pScrn);
2278 struct fppointers fpp;
2280 if (!parse_bit_init_tbl_entry(pScrn, bios, bitentry))
2283 /* If it's not a laptop, you probably don't care about fptables */
2284 /* FIXME: detect mobile BIOS? */
2288 memset(&fpp, 0, sizeof(struct fppointers));
2289 if (bitentry->length > 33) {
2290 fpp.fptablepointer = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 30])));
2291 fpp.fpxlatetableptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 32])));
2292 parse_fp_mode_table(pScrn, bios, &fpp);
2294 if (bitentry->length > 45) {
2295 fpp.lvdsmanufacturerpointer = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 42])));
2296 fpp.fpxlatemanufacturertableptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 44])));
2297 parse_lvds_manufacturer_table(pScrn, bios, &fpp);
2303 static void parse_bit_structure(ScrnInfoPtr pScrn, bios_t *bios, unsigned int offset)
2305 bit_entry_t bitentry;
2309 bitentry.id[0] = bios->data[offset];
2310 bitentry.id[1] = bios->data[offset + 1];
2311 bitentry.length = le16_to_cpu(*((uint16_t *)&bios->data[offset + 2]));
2312 bitentry.offset = le16_to_cpu(*((uint16_t *)&bios->data[offset + 4]));
2314 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2315 "0x%04X: Found BIT command with id 0x%02X (%c)\n",
2316 offset, bitentry.id[0], bitentry.id[0]);
2318 switch (bitentry.id[0]) {
2320 /* id[0] = 0 and id[1] = 0 ==> end of BIT struture */
2321 if (bitentry.id[1] == 0)
2325 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2326 "0x%04X: Found flat panel display table entry in BIT structure.\n", offset);
2327 parse_bit_display_tbl_entry(pScrn, bios, &bitentry);
2330 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2331 "0x%04X: Found init table entry in BIT structure.\n", offset);
2332 parse_bit_init_tbl_entry(pScrn, bios, &bitentry);
2335 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2336 "0x%04X: Found T table entry in BIT structure.\n", offset);
2337 parse_bit_t_tbl_entry(pScrn, bios, &bitentry);
2340 /* TODO: What kind of information does the other BIT entrys point to?
2341 * 'P' entry is probably performance tables, but there are
2342 * quite a few others...
2346 offset += sizeof(bit_entry_t);
2350 static void parse_pins_structure(ScrnInfoPtr pScrn, bios_t *bios, unsigned int offset)
2352 int pins_version_major=bios->data[offset+5];
2353 int pins_version_minor=bios->data[offset+6];
2354 int init1 = bios->data[offset + 18] + (bios->data[offset + 19] * 256);
2355 int init2 = bios->data[offset + 20] + (bios->data[offset + 21] * 256);
2356 int init_size = bios->data[offset + 22] + (bios->data[offset + 23] * 256) + 1;
2359 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PINS version %d.%d\n",
2360 pins_version_major, pins_version_minor);
2363 if (nv_cksum(bios->data + offset, 8)) {
2364 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "bad PINS checksum\n");
2368 switch (pins_version_major) {
2370 ram_tab = init1-0x0010;
2375 ram_tab = bios->data[offset + 24] + (bios->data[offset + 25] * 256);
2381 if ((pins_version_major==5)&&(pins_version_minor>=6)) {
2382 /* VCO range info */
2385 if ((pins_version_major==5)&&(pins_version_minor>=16)) {
2386 bit_entry_t bitentry;
2388 if (pins_version_minor == 0x10)
2389 bitentry.length = 12; /* I've not seen this version, so be "long enough" */
2390 else if (pins_version_minor < 0x14)
2391 bitentry.length = 34;
2393 bitentry.length = 48; /* versions after 0x14 are longer,
2394 but extra contents unneeded ATM */
2396 bitentry.offset = offset + 75;
2397 parse_bmp_table_pointers(pScrn, bios, &bitentry);
2399 /* TODO type1 script */
2403 static unsigned int findstr(bios_t* bios, unsigned char *str, int len)
2407 for (i = 2; i <= (bios->length - len); i++)
2408 if (strncmp((char *)&bios->data[i], (char *)str, len) == 0)
2414 static Bool parse_dcb_entry(uint8_t dcb_version, uint32_t conn, uint32_t conf, struct dcb_entry *entry)
2416 memset(entry, 0, sizeof (struct dcb_entry));
2418 if (dcb_version >= 0x20) {
2419 entry->type = conn & 0xf;
2420 entry->i2c_index = (conn >> 4) & 0xf;
2421 entry->heads = (conn >> 8) & 0xf;
2422 entry->bus = (conn >> 16) & 0xf;
2423 entry->location = (conn >> 20) & 0xf;
2424 entry->or = (conn >> 24) & 0xf;
2425 if ((1 << ffs(entry->or)) * 3 == entry->or)
2426 entry->duallink_possible = TRUE;
2428 entry->duallink_possible = FALSE;
2430 switch (entry->type) {
2432 if (conf & 0xfffffffa)
2433 ErrorF("Unknown LVDS configuration bits, please report\n");
2435 entry->lvdsconf.use_straps_for_mode = TRUE;
2437 entry->lvdsconf.use_power_scripts = TRUE;
2440 } else if (dcb_version >= 0x14 ) {
2441 if (conn != 0xf0003f00) {
2442 ErrorF("Unknown DCB 1.4 entry, please report\n");
2445 /* safe defaults for a crt */
2447 entry->i2c_index = 0;
2450 entry->location = 0;
2452 entry->duallink_possible = FALSE;
2454 // 1.2 needs more loving
2457 entry->i2c_index = 0;
2460 entry->location = 0;
2462 entry->duallink_possible = FALSE;
2469 read_dcb_i2c_table(ScrnInfoPtr pScrn, bios_t *bios, uint8_t dcb_version, uint16_t i2ctabptr)
2471 NVPtr pNv = NVPTR(pScrn);
2473 uint8_t headerlen = 0;
2475 int recordoffset = 0, rdofs = 1, wrofs = 0;
2478 i2c_entries = MAX_NUM_DCB_ENTRIES;
2479 memset(pNv->dcb_table.i2c_read, 0, sizeof(pNv->dcb_table.i2c_read));
2480 memset(pNv->dcb_table.i2c_write, 0, sizeof(pNv->dcb_table.i2c_write));
2482 i2ctable = &bios->data[i2ctabptr];
2484 if (dcb_version >= 0x30) {
2485 if (i2ctable[0] != dcb_version) { /* necessary? */
2486 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2487 "DCB I2C table version mismatch (%02X vs %02X)\n",
2488 i2ctable[0], dcb_version);
2491 headerlen = i2ctable[1];
2492 i2c_entries = i2ctable[2];
2493 if (i2ctable[0] >= 0x40) {
2494 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2495 "G80 DCB I2C table detected, arrgh\n"); /* they're plain weird */
2499 /* it's your own fault if you call this function on a DCB 1.1 BIOS */
2500 if (dcb_version < 0x14) {
2506 for (i = 0; i < i2c_entries; i++) {
2507 if (i2ctable[headerlen + 4 * i + 3] != 0xff) {
2508 pNv->dcb_table.i2c_read[i] = i2ctable[headerlen + recordoffset + rdofs + 4 * i];
2509 pNv->dcb_table.i2c_write[i] = i2ctable[headerlen + recordoffset + wrofs + 4 * i];
2514 static unsigned int parse_dcb_table(ScrnInfoPtr pScrn, bios_t *bios)
2516 NVPtr pNv = NVPTR(pScrn);
2517 uint16_t dcbptr, i2ctabptr = 0;
2519 uint8_t dcb_version, headerlen = 0x4, entries = MAX_NUM_DCB_ENTRIES;
2520 Bool configblock = TRUE;
2521 int recordlength = 8, confofs = 4;
2524 pNv->dcb_table.entries = 0;
2526 /* get the offset from 0x36 */
2527 dcbptr = le16_to_cpu(*(uint16_t *)&bios->data[0x36]);
2529 if (dcbptr == 0x0) {
2530 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2531 "No Display Configuration Block pointer found\n");
2535 dcbtable = &bios->data[dcbptr];
2537 /* get DCB version */
2538 dcb_version = dcbtable[0];
2539 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2540 "Display Configuration Block version %d.%d found\n",
2541 dcb_version >> 4, dcb_version & 0xf);
2543 if (dcb_version >= 0x20) { /* NV17+ */
2546 if (dcb_version >= 0x30) { /* NV40+ */
2547 headerlen = dcbtable[1];
2548 entries = dcbtable[2];
2549 i2ctabptr = le16_to_cpu(*(uint16_t *)&dcbtable[4]);
2550 sig = le32_to_cpu(*(uint32_t *)&dcbtable[6]);
2552 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2553 "DCB header length %02X, with %02X possible entries\n",
2554 headerlen, entries);
2556 /* dcb_block_count = *(dcbtable[1]); */
2557 i2ctabptr = le16_to_cpu(*(uint16_t *)&dcbtable[2]);
2558 sig = le32_to_cpu(*(uint32_t *)&dcbtable[4]);
2562 if (sig != 0x4edcbdcb) {
2563 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2564 "Bad Display Configuration Block signature (%08X)\n", sig);
2567 } else if (dcb_version >= 0x14) { /* some NV15/16, and NV11+ */
2571 strncpy(sig, (char *)&dcbtable[-7], 7);
2572 /* dcb_block_count = *(dcbtable[1]); */
2573 i2ctabptr = le16_to_cpu(*(uint16_t *)&dcbtable[2]);
2577 if (strcmp(sig, "DEV_REC")) {
2578 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2579 "Bad Display Configuration Block signature (%s)\n", sig);
2582 } else if (dcb_version >= 0x12) { /* some NV6/10, and NV15+ */
2583 /* dcb_block_count = *(dcbtable[1]); */
2584 i2ctabptr = le16_to_cpu(*(uint16_t *)&dcbtable[2]);
2585 configblock = FALSE;
2586 } else { /* NV5+, maybe NV4 */
2587 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2588 "Structure of Display Configuration Blocks prior to version 1.2 unknown\n");
2592 if (entries >= MAX_NUM_DCB_ENTRIES)
2593 entries = MAX_NUM_DCB_ENTRIES;
2595 for (i = 0; i < entries; i++) {
2596 uint32_t connection, config = 0;
2598 connection = le32_to_cpu(*(uint32_t *)&dcbtable[headerlen + recordlength * i]);
2600 config = le32_to_cpu(*(uint32_t *)&dcbtable[headerlen + confofs + recordlength * i]);
2602 /* Should we allow discontinuous DCBs? Certainly DCB I2C tables
2603 * can be discontinuous */
2604 if ((connection & 0x0000000f) == 0x0000000f) /* end of records */
2607 ErrorF("Raw DCB entry %d: %08x %08x\n", i, connection, config);
2608 if (!parse_dcb_entry(dcb_version, connection, config, &pNv->dcb_table.entry[i]))
2611 pNv->dcb_table.entries = i;
2613 read_dcb_i2c_table(pScrn, bios, dcb_version, i2ctabptr);
2615 return pNv->dcb_table.entries;
2618 unsigned int NVParseBios(ScrnInfoPtr pScrn)
2620 unsigned int bit_offset;
2621 uint8_t nv_signature[]={0xff,0x7f,'N','V',0x0};
2622 uint8_t bit_signature[]={'B','I','T'};
2626 pNv->dcb_table.entries = 0;
2628 memset(&pNv->VBIOS, 0, sizeof(bios_t));
2629 pNv->VBIOS.execute = FALSE;
2630 pNv->VBIOS.data = xalloc(64 * 1024);
2631 if (!NVShadowVBIOS(pScrn, pNv->VBIOS.data)) {
2632 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2633 "No valid BIOS image found.\n");
2634 xfree(pNv->VBIOS.data);
2637 pNv->VBIOS.length = pNv->VBIOS.data[2] * 512;
2638 if (pNv->VBIOS.length > NV_PROM_SIZE)
2639 pNv->VBIOS.length = NV_PROM_SIZE;
2641 /* parse Display Configuration Block (DCB) table */
2642 if (parse_dcb_table(pScrn, &pNv->VBIOS))
2643 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2644 "Found %d entries in DCB.\n", pNv->dcb_table.entries);
2646 /* check for known signatures */
2647 if ((bit_offset = findstr(&pNv->VBIOS, bit_signature, sizeof(bit_signature)))) {
2648 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIT signature found.\n");
2649 parse_bit_structure(pScrn, &pNv->VBIOS, bit_offset + 4);
2650 } else if ((bit_offset = findstr(&pNv->VBIOS, nv_signature, sizeof(nv_signature)))) {
2651 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV signature found.\n");
2652 parse_pins_structure(pScrn, &pNv->VBIOS, bit_offset);
2654 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2655 "No known script signature found.\n");