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
36 /*#define PERFORM_WRITE*/
42 static int crtchead = 0;
53 uint16_t init_script_tbls_ptr;
54 uint16_t macro_index_tbl_ptr;
55 uint16_t macro_tbl_ptr;
56 uint16_t condition_tbl_ptr;
57 uint16_t io_condition_tbl_ptr;
58 uint16_t io_flag_condition_tbl_ptr;
59 uint16_t init_function_tbl_ptr;
61 uint16_t fptablepointer;
62 uint16_t fpxlatetableptr;
63 uint16_t lvdsmanufacturerpointer;
64 uint16_t fpxlatemanufacturertableptr;
67 static uint16_t le16_to_cpu(const uint16_t x)
69 #if X_BYTE_ORDER == X_BIG_ENDIAN
76 static uint32_t le32_to_cpu(const uint32_t x)
78 #if X_BYTE_ORDER == X_BIG_ENDIAN
85 static Bool nv_cksum(const uint8_t *data, unsigned int length)
87 /* there's a few checksums in the BIOS, so here's a generic checking function */
91 for (i = 0; i < length; i++)
100 static int NVValidVBIOS(ScrnInfoPtr pScrn, const uint8_t *data)
102 /* check for BIOS signature */
103 if (!(data[0] == 0x55 && data[1] == 0xAA)) {
104 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
105 "... BIOS signature not found\n");
109 if (nv_cksum(data, data[2] * 512)) {
110 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
111 "... BIOS checksum invalid\n");
112 /* probably ought to set a do_not_execute flag for table parsing here,
113 * assuming most BIOSen are valid */
116 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "... appears to be valid\n");
121 static void NVShadowVBIOS_PROM(ScrnInfoPtr pScrn, uint8_t *data)
123 NVPtr pNv = NVPTR(pScrn);
126 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
127 "Attempting to locate BIOS image in PROM\n");
129 /* enable ROM access */
130 nvWriteMC(pNv, 0x1850, 0x0);
131 for (i = 0; i < NV_PROM_SIZE; i++) {
132 /* according to nvclock, we need that to work around a 6600GT/6800LE bug */
133 data[i] = pNv->PROM[i];
134 data[i] = pNv->PROM[i];
135 data[i] = pNv->PROM[i];
136 data[i] = pNv->PROM[i];
137 data[i] = pNv->PROM[i];
139 /* disable ROM access */
140 nvWriteMC(pNv, 0x1850, 0x1);
143 static void NVShadowVBIOS_PRAMIN(ScrnInfoPtr pScrn, uint32_t *data)
145 NVPtr pNv = NVPTR(pScrn);
146 const uint32_t *pramin = (uint32_t *)&pNv->REGS[NV_PRAMIN_ROM_OFFSET/4];
147 uint32_t old_bar0_pramin = 0;
149 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
150 "Attempting to locate BIOS image in PRAMIN\n");
152 if (pNv->Architecture >= NV_ARCH_50) {
155 vbios_vram = (pNv->REGS[0x619f04/4] & ~0xff) << 8;
157 vbios_vram = pNv->REGS[0x1700/4] << 16;
158 vbios_vram += 0xf0000;
161 old_bar0_pramin = pNv->REGS[0x1700/4];
162 pNv->REGS[0x1700/4] = vbios_vram >> 16;
165 memcpy(data, pramin, NV_PROM_SIZE);
167 if (pNv->Architecture >= NV_ARCH_50) {
168 pNv->REGS[0x1700/4] = old_bar0_pramin;
172 static Bool NVShadowVBIOS(ScrnInfoPtr pScrn, uint32_t *data)
174 NVShadowVBIOS_PROM(pScrn, (uint8_t *)data);
175 if (NVValidVBIOS(pScrn, (uint8_t *)data) == 2)
178 NVShadowVBIOS_PRAMIN(pScrn, data);
179 if (NVValidVBIOS(pScrn, (uint8_t *)data))
190 int length_multiplier;
191 Bool (*handler)(ScrnInfoPtr pScrn, bios_t *, uint16_t, init_exec_t *);
200 static void parse_init_table(ScrnInfoPtr pScrn, bios_t *bios, unsigned int offset, init_exec_t *iexec);
202 #define MACRO_INDEX_SIZE 2
204 #define CONDITION_SIZE 12
205 #define IO_FLAG_CONDITION_SIZE 9
213 static int nv_valid_reg(uint32_t reg)
215 #define WITHIN(x,y,z) ((x>=y)&&(x<y+z))
216 if (WITHIN(reg,NV_PRAMIN_OFFSET,NV_PRAMIN_SIZE))
218 if (WITHIN(reg,NV_PCRTC0_OFFSET,NV_PCRTC0_SIZE))
220 if (WITHIN(reg,NV_PRAMDAC0_OFFSET,NV_PRAMDAC0_SIZE))
222 if (WITHIN(reg,NV_PFB_OFFSET,NV_PFB_SIZE))
224 if (WITHIN(reg,NV_PFIFO_OFFSET,NV_PFIFO_SIZE))
226 if (WITHIN(reg,NV_PGRAPH_OFFSET,NV_PGRAPH_SIZE))
228 if (WITHIN(reg,NV_PEXTDEV_OFFSET,NV_PEXTDEV_SIZE))
230 if (WITHIN(reg,NV_PTIMER_OFFSET,NV_PTIMER_SIZE))
232 if (WITHIN(reg,NV_PVIDEO_OFFSET,NV_PVIDEO_SIZE))
234 if (WITHIN(reg,NV_PMC_OFFSET,NV_PMC_SIZE))
236 if (WITHIN(reg,NV_FIFO_OFFSET,NV_FIFO_SIZE))
238 if (WITHIN(reg,NV_PCIO0_OFFSET,NV_PCIO0_SIZE))
240 if (WITHIN(reg,NV_PDIO0_OFFSET,NV_PDIO0_SIZE))
242 if (WITHIN(reg,NV_PVIO_OFFSET,NV_PVIO_SIZE))
244 if (WITHIN(reg,NV_PROM_OFFSET,NV_PROM_SIZE))
246 if (WITHIN(reg,NV_PRAMIN_ROM_OFFSET,NV_PROM_SIZE))
252 static void nv32_rd(ScrnInfoPtr pScrn, uint32_t reg, uint32_t *data)
254 NVPtr pNv = NVPTR(pScrn);
256 if (!nv_valid_reg(reg)) {
257 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
258 "========= unknown reg 0x%08X ==========\n", reg);
261 *data = pNv->REGS[reg/4];
263 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
264 " Read: Reg: 0x%08X, Data: 0x%08X\n", reg, *data);
267 static int nv32_wr(ScrnInfoPtr pScrn, uint32_t reg, uint32_t data)
269 if (DEBUGLEVEL >= 8) {
271 nv32_rd(pScrn, reg, &tmp);
274 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
275 " Write: Reg: 0x%08X, Data: 0x%08X\n", reg, data);
276 if (!nv_valid_reg(reg)) {
277 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
278 "========= unknown reg 0x%08X ==========\n", reg);
283 NVPtr pNv = NVPTR(pScrn);
284 pNv->REGS[reg/4] = data;
289 static void nv_port_rd(ScrnInfoPtr pScrn, uint16_t port, uint8_t index, uint8_t *data)
291 NVPtr pNv = NVPTR(pScrn);
292 volatile uint8_t *ptr = crtchead ? pNv->PCIO1 : pNv->PCIO0;
294 VGA_WR08(ptr, port, index);
295 *data = VGA_RD08(ptr, port + 1);
298 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
299 " Indexed read: Port: 0x%04X, Index: 0x%02X, Head: 0x%02X, Data: 0x%02X\n",
300 port, index, crtchead, *data);
303 static void nv_port_wr(ScrnInfoPtr pScrn, uint16_t port, uint8_t index, uint8_t data)
305 NVPtr pNv = NVPTR(pScrn);
306 volatile uint8_t *ptr;
308 if (port == CRTC_INDEX_COLOR && index == NV_VGA_CRTCX_OWNER && data != NV_VGA_CRTCX_OWNER_HEADB)
310 ptr = crtchead ? pNv->PCIO1 : pNv->PCIO0;
312 if (DEBUGLEVEL >= 8) {
314 nv_port_rd(pScrn, port, index, &tmp);
317 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
318 " Indexed write: Port: 0x%04X, Index: 0x%02X, Head: 0x%02X, Data: 0x%02X\n",
319 port, index, crtchead, data);
323 VGA_WR08(ptr, port, index);
324 VGA_WR08(ptr, port + 1, data);
326 if (port == CRTC_INDEX_COLOR && index == NV_VGA_CRTCX_OWNER && data == NV_VGA_CRTCX_OWNER_HEADB)
330 static Bool io_flag_condition(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, uint8_t cond)
332 /* The IO flag condition entry has 2 bytes for the CRTC port; 1 byte
333 * for the CRTC index; 1 byte for the mask to apply to the value
334 * retrieved from the CRTC; 1 byte for the shift right to apply to the
335 * masked CRTC value; 2 bytes for the offset to the flag array, to
336 * which the shifted value is added; 1 byte for the mask applied to the
337 * value read from the flag array; and 1 byte for the value to compare
338 * against the masked byte from the flag table.
341 uint16_t condptr = bios->io_flag_condition_tbl_ptr + cond * IO_FLAG_CONDITION_SIZE;
342 uint16_t crtcport = le16_to_cpu(*((uint16_t *)(&bios->data[condptr])));
343 uint8_t crtcindex = bios->data[condptr + 2];
344 uint8_t mask = bios->data[condptr + 3];
345 uint8_t shift = bios->data[condptr + 4];
346 uint16_t flagarray = le16_to_cpu(*((uint16_t *)(&bios->data[condptr + 5])));
347 uint8_t flagarraymask = bios->data[condptr + 7];
348 uint8_t cmpval = bios->data[condptr + 8];
352 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
353 "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, Shift: 0x%02X, FlagArray: 0x%04X, FAMask: 0x%02X, Cmpval: 0x%02X\n",
354 offset, crtcport, crtcindex, mask, shift, flagarray, flagarraymask, cmpval);
356 nv_port_rd(pScrn, crtcport, crtcindex, &data);
358 data = bios->data[flagarray + ((data & mask) >> shift)];
359 data &= flagarraymask;
362 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
363 "0x%04X: Checking if 0x%02X equals 0x%02X\n",
364 offset, data, cmpval);
372 static Bool init_prog(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
374 /* INIT_PROG opcode: 0x31
376 * offset (8 bit): opcode
377 * offset + 1 (32 bit): reg
378 * offset + 5 (32 bit): and mask
379 * offset + 9 (8 bit): shift right
380 * offset + 10 (8 bit): number of configurations
381 * offset + 11 (32 bit): register
382 * offset + 15 (32 bit): configuration 1
385 * Starting at offset + 15 there are "number of configurations"
386 * 32 bit values. To find out which configuration value to use
387 * read "CRTC reg" on the CRTC controller with index "CRTC index"
388 * and bitwise AND this value with "and mask" and then bit shift the
389 * result "shift right" bits to the right.
390 * Assign "register" with appropriate configuration value.
393 CARD32 reg = *((CARD32 *) (&bios->data[offset + 1]));
394 CARD32 and = *((CARD32 *) (&bios->data[offset + 5]));
395 CARD8 shiftr = *((CARD8 *) (&bios->data[offset + 9]));
396 CARD8 nr = *((CARD8 *) (&bios->data[offset + 10]));
397 CARD32 reg2 = *((CARD32 *) (&bios->data[offset + 11]));
399 CARD32 configval, tmp;
401 if (iexec->execute) {
402 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: REG: 0x%04X\n", offset,
405 nv32_rd(pScrn, reg, &tmp);
406 configuration = (tmp & and) >> shiftr;
408 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CONFIGURATION TO USE: 0x%02X\n",
409 offset, configuration);
411 if (configuration <= nr) {
414 *((CARD32 *) (&bios->data[offset + 15 + configuration * 4]));
416 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: REG: 0x%08X, VALUE: 0x%08X\n", offset,
419 nv32_rd(pScrn, reg2, &tmp);
420 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%08X\n",
422 nv32_wr(pScrn, reg2, configval);
428 static Bool init_io_restrict_prog(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
430 /* INIT_IO_RESTRICT_PROG opcode: 0x32 ('2')
432 * offset (8 bit): opcode
433 * offset + 1 (16 bit): CRTC port
434 * offset + 3 (8 bit): CRTC index
435 * offset + 4 (8 bit): mask
436 * offset + 5 (8 bit): shift
437 * offset + 6 (8 bit): count
438 * offset + 7 (32 bit): register
439 * offset + 11 (32 bit): configuration 1
442 * Starting at offset + 11 there are "count" 32 bit values.
443 * To find out which value to use read index "CRTC index" on "CRTC port",
444 * AND this value with "mask" and then bit shift right "shift" bits.
445 * Read the appropriate value using this index and write to "register"
448 uint16_t crtcport = le16_to_cpu(*((uint16_t *)(&bios->data[offset + 1])));
449 uint8_t crtcindex = bios->data[offset + 3];
450 uint8_t mask = bios->data[offset + 4];
451 uint8_t shift = bios->data[offset + 5];
452 uint8_t count = bios->data[offset + 6];
453 uint32_t reg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 7])));
461 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
462 "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, Shift: 0x%02X, Count: 0x%02X, Reg: 0x%08X\n",
463 offset, crtcport, crtcindex, mask, shift, count, reg);
465 nv_port_rd(pScrn, crtcport, crtcindex, &config);
466 config = (config & mask) >> shift;
467 if (config > count) {
468 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
469 "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
470 offset, config, count);
474 configval = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 11 + config * 4])));
477 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
478 "0x%04X: Writing config %02X\n", offset, config);
480 nv32_wr(pScrn, reg, configval);
485 static Bool init_repeat(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
487 /* INIT_REPEAT opcode: 0x33 ('3')
489 * offset (8 bit): opcode
490 * offset + 1 (8 bit): count
492 * Execute script following this opcode up to INIT_REPEAT_END
496 uint8_t count = bios->data[offset + 1];
499 /* no iexec->execute check by design */
501 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
502 "0x%04X: REPEATING FOLLOWING SEGMENT %d TIMES.\n",
505 iexec->repeat = TRUE;
507 /* count - 1, as the script block will execute once when we leave this
508 * opcode -- this is compatible with bios behaviour as:
509 * a) the block is always executed at least once, even if count == 0
510 * b) the bios interpreter skips to the op following INIT_END_REPEAT,
513 for (i = 0; i < count - 1; i++)
514 parse_init_table(pScrn, bios, offset + 2, iexec);
516 iexec->repeat = FALSE;
521 static Bool init_io_restrict_pll(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
523 /* INIT_IO_RESTRICT_PLL opcode: 0x34 ('4')
525 * offset (8 bit): opcode
526 * offset + 1 (16 bit): CRTC port
527 * offset + 3 (8 bit): CRTC index
528 * offset + 4 (8 bit): mask
529 * offset + 5 (8 bit): shift
530 * offset + 6 (8 bit): IO flag condition index
531 * offset + 7 (8 bit): count
532 * offset + 8 (32 bit): register
533 * offset + 12 (16 bit): frequency 1
536 * Starting at offset + 12 there are "count" 16 bit frequencies (10kHz).
537 * Set PLL register "register" to coefficients for frequency n,
538 * selected by reading index "CRTC index" of "CRTC port" ANDed with
539 * "mask" and shifted right by "shift". If "IO flag condition index" > 0,
540 * and condition met, double frequency before setting it.
543 uint16_t crtcport = le16_to_cpu(*((uint16_t *)(&bios->data[offset + 1])));
544 uint8_t crtcindex = bios->data[offset + 3];
545 uint8_t mask = bios->data[offset + 4];
546 uint8_t shift = bios->data[offset + 5];
547 int8_t io_flag_condition_idx = bios->data[offset + 6];
548 uint8_t count = bios->data[offset + 7];
549 uint32_t reg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 8])));
557 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
558 "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, Shift: 0x%02X, IO Flag Condition: 0x%02X, Count: 0x%02X, Reg: 0x%08X\n",
559 offset, crtcport, crtcindex, mask, shift, io_flag_condition_idx, count, reg);
561 nv_port_rd(pScrn, crtcport, crtcindex, &config);
562 config = (config & mask) >> shift;
563 if (config > count) {
564 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
565 "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
566 offset, config, count);
570 freq = le16_to_cpu(*((uint16_t *)(&bios->data[offset + 12 + config * 2])));
572 if (io_flag_condition_idx > 0) {
573 if (io_flag_condition(pScrn, bios, offset, io_flag_condition_idx)) {
574 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
575 "0x%04X: CONDITION FULFILLED - FREQ DOUBLED\n", offset);
578 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
579 "0x%04X: CONDITION IS NOT FULFILLED. FREQ UNCHANGED\n", offset);
583 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
584 "0x%04X: Reg: 0x%08X, Config: 0x%02X, Freq: %d0kHz\n",
585 offset, reg, config, freq);
587 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
592 configval = 0x01014E07;
595 configval = 0x13030E02;
602 static Bool init_end_repeat(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
604 /* INIT_END_REPEAT opcode: 0x36 ('6')
606 * offset (8 bit): opcode
608 * Marks the end of the block for INIT_REPEAT to repeat
611 /* no iexec->execute check by design */
613 /* iexec->repeat flag necessary to go past INIT_END_REPEAT opcode when
614 * we're not in repeat mode
622 static Bool init_copy(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
624 /* INIT_COPY opcode: 0x37 ('7')
626 * offset (8 bit): opcode
627 * offset + 1 (32 bit): register
628 * offset + 5 (8 bit): shift
629 * offset + 6 (8 bit): srcmask
630 * offset + 7 (16 bit): CRTC port
631 * offset + 9 (8 bit): CRTC index
632 * offset + 10 (8 bit): mask
634 * Read index "CRTC index" on "CRTC port", AND with "mask", OR with
635 * (REGVAL("register") >> "shift" & "srcmask") and write-back to CRTC port
638 uint32_t reg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 1])));
639 uint8_t shift = bios->data[offset + 5];
640 uint8_t srcmask = bios->data[offset + 6];
641 uint16_t crtcport = le16_to_cpu(*((uint16_t *)(&bios->data[offset + 7])));
642 uint8_t crtcindex = bios->data[offset + 9];
643 uint8_t mask = bios->data[offset + 10];
651 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
652 "0x%04X: Reg: 0x%08X, Shift: 0x%02X, SrcMask: 0x%02X, Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X\n",
653 offset, reg, shift, srcmask, crtcport, crtcindex, mask);
655 nv32_rd(pScrn, reg, &data);
660 data <<= (0x100 - shift);
664 nv_port_rd(pScrn, crtcport, crtcindex, &crtcdata);
665 crtcdata = (crtcdata & mask) | (uint8_t)data;
666 nv_port_wr(pScrn, crtcport, crtcindex, crtcdata);
671 static Bool init_not(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
673 /* INIT_NOT opcode: 0x38 ('8')
675 * offset (8 bit): opcode
677 * Invert the current execute / no-execute condition (i.e. "else")
680 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
681 "0x%04X: ------ SKIPPING FOLLOWING COMMANDS ------\n", offset);
683 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
684 "0x%04X: ------ EXECUTING FOLLOWING COMMANDS ------\n", offset);
686 iexec->execute = !iexec->execute;
690 static Bool init_io_flag_condition(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
692 /* INIT_IO_FLAG_CONDITION opcode: 0x39 ('9')
694 * offset (8 bit): opcode
695 * offset + 1 (8 bit): condition number
697 * Check condition "condition number" in the IO flag condition table.
698 * If condition not met skip subsequent opcodes until condition
699 * is inverted (INIT_NOT), or we hit INIT_RESUME
702 uint8_t cond = bios->data[offset + 1];
707 if (io_flag_condition(pScrn, bios, offset, cond))
708 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
709 "0x%04X: CONDITION FULFILLED - CONTINUING TO EXECUTE\n", offset);
711 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
712 "0x%04X: CONDITION IS NOT FULFILLED.\n", offset);
713 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
714 "0x%04X: ------ SKIPPING FOLLOWING COMMANDS ------\n", offset);
715 iexec->execute = FALSE;
721 Bool init_idx_addr_latched(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
723 /* INIT_INDEX_ADDRESS_LATCHED opcode: 0x49 ('I')
725 * offset (8 bit): opcode
726 * offset + 1 (32 bit): control register
727 * offset + 5 (32 bit): data register
728 * offset + 9 (32 bit): mask
729 * offset + 13 (32 bit): data
730 * offset + 17 (8 bit): count
731 * offset + 18 (8 bit): address 1
732 * offset + 19 (8 bit): data 1
735 * For each of "count" address and data pairs, write "data n" to "data register",
736 * read the current value of "control register", and write it back once ANDed
737 * with "mask", ORed with "data", and ORed with "address n"
740 uint32_t controlreg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 1])));
741 uint32_t datareg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 5])));
742 uint32_t mask = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 9])));
743 uint32_t data = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 13])));
744 uint8_t count = bios->data[offset + 17];
752 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
753 "0x%04X: ControlReg: 0x%08X, DataReg: 0x%08X, Mask: 0x%08X, Data: 0x%08X, Count: 0x%02X\n",
754 offset, controlreg, datareg, mask, data, count);
756 for (i = 0; i < count; i++) {
757 uint8_t instaddress = bios->data[offset + 18 + i * 2];
758 uint8_t instdata = bios->data[offset + 19 + i * 2];
761 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
762 "0x%04X: Address: 0x%02X, Data: 0x%02X\n", offset, instaddress, instdata);
764 nv32_wr(pScrn, datareg, instdata);
766 nv32_rd(pScrn, controlreg, &value);
767 value = (value & mask) | data | instaddress;
769 nv32_wr(pScrn, controlreg, value);
775 static Bool init_io_restrict_pll2(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
777 /* INIT_IO_RESTRICT_PLL2 opcode: 0x4A ('J')
779 * offset (8 bit): opcode
780 * offset + 1 (16 bit): CRTC port
781 * offset + 3 (8 bit): CRTC index
782 * offset + 4 (8 bit): mask
783 * offset + 5 (8 bit): shift
784 * offset + 6 (8 bit): count
785 * offset + 7 (32 bit): register
786 * offset + 11 (32 bit): frequency 1
789 * Starting at offset + 11 there are "count" 32 bit frequencies (kHz).
790 * Set PLL register "register" to coefficients for frequency n,
791 * selected by reading index "CRTC index" of "CRTC port" ANDed with
792 * "mask" and shifted right by "shift".
795 uint16_t crtcport = le16_to_cpu(*((uint16_t *)(&bios->data[offset + 1])));
796 uint8_t crtcindex = bios->data[offset + 3];
797 uint8_t mask = bios->data[offset + 4];
798 uint8_t shift = bios->data[offset + 5];
799 uint8_t count = bios->data[offset + 6];
800 uint32_t reg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 7])));
808 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
809 "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, Shift: 0x%02X, Count: 0x%02X, Reg: 0x%08X\n",
810 offset, crtcport, crtcindex, mask, shift, count, reg);
815 nv_port_rd(pScrn, crtcport, crtcindex, &config);
816 config = (config & mask) >> shift;
817 if (config > count) {
818 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
819 "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
820 offset, config, count);
824 freq = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 11 + config * 4])));
827 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
828 "0x%04X: Reg: 0x%08X, Config: 0x%02X, Freq: %dkHz\n",
829 offset, reg, config, freq);
831 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
836 static Bool init_pll2(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
838 /* INIT_PLL2 opcode: 0x4B ('K')
840 * offset (8 bit): opcode
841 * offset + 1 (32 bit): register
842 * offset + 5 (32 bit): freq
844 * Set PLL register "register" to coefficients for frequency "freq"
847 uint32_t reg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 1])));
848 uint32_t freq = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 5])));
854 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
855 "0x%04X: Reg: 0x%04X, Freq: %dkHz\n",
858 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
863 Bool init_50(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
865 /* INIT_50 opcode: 0x50 ('P')
867 * offset (8 bit): opcode
868 * offset + 1 (8 bit): magic lookup value
869 * offset + 2 (8 bit): count
870 * offset + 3 (8 bit): addr 1
871 * offset + 4 (8 bit): data 1
874 * For each of "count" TMDS address and data pairs write "data n" to "addr n"
875 * "magic lookup value" (mlv) determines which TMDS base address is used:
876 * For mlv < 80, it is an index into a table of TMDS base addresses
877 * For mlv == 80 use the "or" value of the dcb_entry indexed by CR58 for CR57 = 0
878 * to index a table of offsets to the basic 0x6808b0 address
879 * For mlv == 81 use the "or" value of the dcb_entry indexed by CR58 for CR57 = 0
880 * to index a table of offsets to the basic 0x6808b0 address, and then flip the offset by 8
882 NVPtr pNv = NVPTR(pScrn);
883 uint8_t mlv = bios->data[offset + 1];
884 uint8_t count = bios->data[offset + 2];
888 int pramdac_offset[13] = {0, 0, 0x8, 0, 0x2000, 0, 0, 0, 0x2008, 0, 0, 0, 0x2000};
889 uint32_t pramdac_table[4] = {0x6808b0, 0x6808b8, 0x6828b0, 0x6828b8};
895 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
896 "0x%04X: MagicLookupValue: 0x%02X, Count: 0x%02X\n",
899 /* here we assume that the DCB table has already been parsed */
902 nv_port_wr(pScrn, CRTC_INDEX_COLOR, 0x57, 0);
903 nv_port_rd(pScrn, CRTC_INDEX_COLOR, 0x58, &dcb_entry);
904 if (dcb_entry > pNv->dcb_table.entries) {
905 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
906 "0x%04X: CR58 doesn't have a valid DCB entry currently (%02X)\n",
910 dacoffset = pramdac_offset[pNv->dcb_table.entry[dcb_entry].or];
913 reg = 0x6808b0 + dacoffset;
915 reg = pramdac_table[mlv];
917 for (i = 0; i < count; i++) {
918 uint8_t tmds_addr = bios->data[offset + 3 + i * 2];
919 uint8_t tmds_data = bios->data[offset + 4 + i * 2];
921 nv32_wr(pScrn, reg + 4, tmds_data);
922 nv32_wr(pScrn, reg, tmds_addr);
928 Bool init_cr_idx_adr_latch(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
930 /* INIT_CR_INDEX_ADDRESS_LATCHED opcode: 0x51 ('Q')
932 * offset (8 bit): opcode
933 * offset + 1 (8 bit): CRTC index1
934 * offset + 2 (8 bit): CRTC index2
935 * offset + 3 (8 bit): baseaddr
936 * offset + 4 (8 bit): count
937 * offset + 5 (8 bit): data 1
940 * For each of "count" address and data pairs, write "baseaddr + n" to
941 * "CRTC index1" and "data n" to "CRTC index2"
942 * Once complete, restore initial value read from "CRTC index1"
944 uint8_t crtcindex1 = bios->data[offset + 1];
945 uint8_t crtcindex2 = bios->data[offset + 2];
946 uint8_t baseaddr = bios->data[offset + 3];
947 uint8_t count = bios->data[offset + 4];
948 uint8_t oldaddr, data;
955 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
956 "0x%04X: Index1: 0x%02X, Index2: 0x%02X, BaseAddr: 0x%02X, Count: 0x%02X\n",
957 offset, crtcindex1, crtcindex2, baseaddr, count);
959 nv_port_rd(pScrn, CRTC_INDEX_COLOR, crtcindex1, &oldaddr);
961 for (i = 0; i < count; i++) {
962 nv_port_wr(pScrn, CRTC_INDEX_COLOR, crtcindex1, baseaddr + i);
964 data = bios->data[offset + 5 + i];
965 nv_port_wr(pScrn, CRTC_INDEX_COLOR, crtcindex2, data);
968 nv_port_wr(pScrn, CRTC_INDEX_COLOR, crtcindex1, oldaddr);
973 Bool init_cr(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
975 /* INIT_CR opcode: 0x52 ('R')
977 * offset (8 bit): opcode
978 * offset + 1 (8 bit): CRTC index
979 * offset + 2 (8 bit): mask
980 * offset + 3 (8 bit): data
982 * Assign the value of at "CRTC index" ANDed with mask and ORed with data
983 * back to "CRTC index"
986 uint8_t crtcindex = bios->data[offset + 1];
987 uint8_t mask = bios->data[offset + 2];
988 uint8_t data = bios->data[offset + 3];
995 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
996 "0x%04X: Index: 0x%02X, Mask: 0x%02X, Data: 0x%02X\n",
997 offset, crtcindex, mask, data);
999 nv_port_rd(pScrn, CRTC_INDEX_COLOR, crtcindex, &value);
1001 value = (value & mask) | data;
1003 nv_port_wr(pScrn, CRTC_INDEX_COLOR, crtcindex, value);
1008 static Bool init_zm_cr(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1010 /* INIT_ZM_CR opcode: 0x53 ('S')
1012 * offset (8 bit): opcode
1013 * offset + 1 (8 bit): CRTC index
1014 * offset + 2 (8 bit): value
1016 * Assign "value" to CRTC register with index "CRTC index".
1019 uint8_t crtcindex = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 1])));
1020 uint8_t data = bios->data[offset + 2];
1022 if (!iexec->execute)
1025 nv_port_wr(pScrn, CRTC_INDEX_COLOR, crtcindex, data);
1030 static Bool init_zm_cr_group(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1032 /* INIT_ZM_CR opcode: 0x54 ('T')
1034 * offset (8 bit): opcode
1035 * offset + 1 (8 bit): count
1036 * offset + 2 (8 bit): CRTC index 1
1037 * offset + 3 (8 bit): value 1
1040 * For "count", assign "value n" to CRTC register with index "CRTC index n".
1043 uint8_t count = bios->data[offset + 1];
1046 if (!iexec->execute)
1049 for (i = 0; i < count; i++)
1050 init_zm_cr(pScrn, bios, offset + 2 + 2 * i - 1, iexec);
1055 static Bool init_condition_time(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1057 /* My BIOS does not use this command. */
1058 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
1063 static Bool init_zm_reg_sequence(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1065 /* INIT_ZM_REG_SEQUENCE opcode: 0x58 ('X')
1067 * offset (8 bit): opcode
1068 * offset + 1 (32 bit): base register
1069 * offset + 5 (8 bit): count
1070 * offset + 6 (32 bit): value 1
1073 * Starting at offset + 6 there are "count" 32 bit values.
1074 * For "count" iterations set "base register" + 4 * current_iteration
1075 * to "value current_iteration"
1078 uint32_t basereg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 1])));
1079 uint32_t count = bios->data[offset + 5];
1082 if (!iexec->execute)
1085 if (DEBUGLEVEL >= 6)
1086 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1087 "0x%04X: BaseReg: 0x%08X, Count: 0x%02X\n",
1088 offset, basereg, count);
1090 for (i = 0; i < count; i++) {
1091 uint32_t reg = basereg + i * 4;
1093 if ((reg & 0xffc) == 0x3c0)
1094 ErrorF("special case: FIXME\n");
1095 if ((reg & 0xffc) == 0x3cc)
1096 ErrorF("special case: FIXME\n");
1098 uint32_t data = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 6 + i * 4])));
1100 nv32_wr(pScrn, reg, data);
1106 static Bool init_indirect_reg(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1108 /* INIT_INDIRECT_REG opcode: 0x5A
1110 * offset (8 bit): opcode
1111 * offset + 1 (32 bit): register
1112 * offset + 5 (16 bit): adress offset (in bios)
1114 * Lookup value at offset data in the bios and write it to reg
1116 NVPtr pNv = NVPTR(pScrn);
1117 CARD32 reg = *((CARD32 *) (&bios->data[offset + 1]));
1118 CARD16 data = le16_to_cpu(*((CARD16 *) (&bios->data[offset + 5])));
1119 CARD32 data2 = bios->data[data];
1121 if (iexec->execute) {
1122 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1123 "0x%04X: REG: 0x%04X, DATA AT: 0x%04X, VALUE IS: 0x%08X\n",
1124 offset, reg, data, data2);
1126 if (DEBUGLEVEL >= 6) {
1128 nv32_rd(pScrn, reg, &tmpval);
1129 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%08X\n", offset, tmpval);
1132 nv32_wr(pScrn, reg, data2);
1137 static Bool init_sub_direct(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1139 /* INIT_SUB_DIRECT opcode: 0x5B ('[')
1141 * offset (8 bit): opcode
1142 * offset + 1 (16 bit): subroutine offset (in bios)
1144 * Calls a subroutine that will execute commands until INIT_DONE
1148 uint16_t sub_offset = le16_to_cpu(*((uint16_t *) (&bios->data[offset + 1])));
1150 if (!iexec->execute)
1153 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: EXECUTING SUB-ROUTINE AT 0x%04X\n",
1154 offset, sub_offset);
1156 parse_init_table(pScrn, bios, sub_offset, iexec);
1158 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: END OF SUB-ROUTINE AT 0x%04X\n",
1159 offset, sub_offset);
1164 static Bool init_copy_nv_reg(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1166 CARD32 srcreg = *((CARD32 *) (&bios->data[offset + 1]));
1167 CARD8 shift = *((CARD8 *) (&bios->data[offset + 5]));
1168 CARD32 and1 = *((CARD32 *) (&bios->data[offset + 6]));
1169 CARD32 xor = *((CARD32 *) (&bios->data[offset + 10]));
1170 CARD32 dstreg = *((CARD32 *) (&bios->data[offset + 14]));
1171 CARD32 and2 = *((CARD32 *) (&bios->data[offset + 18]));
1175 if (iexec->execute) {
1176 nv32_rd(pScrn, srcreg, &srcdata);
1183 srcdata = (srcdata & and1) ^ xor;
1185 nv32_rd(pScrn, dstreg, &dstdata);
1191 nv32_rd(pScrn, dstreg, &tmp);
1193 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: REG: 0x%08X, VALUE: 0x%08X\n", offset, dstreg,
1196 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%08X\n", offset, tmp);
1198 nv32_wr(pScrn, dstreg, dstdata);
1203 static Bool init_zm_index_io(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1205 /* INIT_ZM_INDEX_IO opcode: 0x62 ('b')
1207 * offset (8 bit): opcode
1208 * offset + 1 (16 bit): CRTC port
1209 * offset + 3 (8 bit): CRTC index
1210 * offset + 4 (8 bit): data
1212 * Write "data" to index "CRTC index" of "CRTC port"
1214 uint16_t crtcport = le16_to_cpu(*((uint16_t *)(&bios->data[offset + 1])));
1215 uint8_t crtcindex = bios->data[offset + 3];
1216 uint8_t data = bios->data[offset + 4];
1218 if (!iexec->execute)
1221 nv_port_wr(pScrn, crtcport, crtcindex, data);
1226 static Bool init_compute_mem(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1228 /* INIT_COMPUTE_MEM opcode: 0x63 ('c')
1230 * offset (8 bit): opcode
1235 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
1237 uint16_t ramcfg = le16_to_cpu(*((uint16_t *)(&bios->data[bios->ram_table_offset])));
1242 if (!iexec->execute)
1245 nv32_rd(pScrn, 0x00101000, &strapinfo);
1246 nv32_rd(pScrn, 0x00100080, &pfb_debug);
1248 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "STRAPINFO: 0x%08X\n", strapinfo);
1249 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PFB_DEBUG: 0x%08X\n", pfb_debug);
1250 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RAM CFG: 0x%04X\n", ramcfg);
1252 pfb_debug &= 0xffffffef;
1254 strapinfo &= 0x0000000f;
1255 ramcfg2 = le16_to_cpu(*((uint16_t *)
1256 (&bios->data[bios->ram_table_offset + (2 * strapinfo)])));
1258 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "AFTER MANIPULATION\n");
1259 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "STRAPINFO: 0x%08X\n", strapinfo);
1260 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PFB_DEBUG: 0x%08X\n", pfb_debug);
1261 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RAM CFG2: 0x%08X\n", ramcfg2);
1267 nv32_rd(pScrn, 0x00100200, ®1);
1268 nv32_rd(pScrn, 0x0010020C, ®2);
1270 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x00100200: 0x%08X\n", reg1);
1271 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x0010020C: 0x%08X\n", reg2);
1277 static Bool init_reset(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1279 /* INIT_RESET opcode: 0x65 ('e')
1281 * offset (8 bit): opcode
1282 * offset + 1 (32 bit): register
1283 * offset + 5 (32 bit): value1
1284 * offset + 9 (32 bit): value2
1286 * Assign "value1" to "register", then assign "value2" to "register"
1289 uint32_t reg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 1])));
1290 uint32_t value1 = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 5])));
1291 uint32_t value2 = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 9])));
1294 if (!iexec->execute)
1297 if (DEBUGLEVEL >= 6)
1298 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1299 "0x%04X: Reg: 0x%08X, Value1: 0x%08X, Value2: 0x%08X\n",
1300 offset, reg, value1, value2);
1302 /* it's not clear from my .dmp file, but it seems we should zero out NV_PBUS_PCI_NV_19(0x0000184C) and then restore it */
1303 nv32_rd(pScrn, NV_PBUS_PCI_NV_19, &pci_nv_19);
1305 nv32_rd(pScrn, PCICFG(PCICFG_ROMSHADOW), &tmpval);
1306 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: PCICFG_ROMSHADOW: 0x%02X\n", offset, tmpval);
1308 nv32_wr(pScrn, NV_PBUS_PCI_NV_19, 0);
1309 nv32_wr(pScrn, reg, value1);
1310 nv32_wr(pScrn, reg, value2);
1311 nv32_wr(pScrn, NV_PBUS_PCI_NV_19, pci_nv_19);
1313 /* PCI Config space init needs to be added here. */
1314 /* if (nv32_rd(pScrn, PCICFG(PCICFG_ROMSHADOW), value1)) */
1315 /* nv32_wr(pScrn, PCICFG(PCICFG_ROMSHADOW), value1 & 0xfffffffe) */
1320 static Bool init_index_io8(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1322 /* INIT_INDEX_IO8 opcode: 0x69
1324 * offset (8 bit): opcode
1325 * offset + 1 (16 bit): CRTC reg
1326 * offset + 3 (8 bit): and mask
1327 * offset + 4 (8 bit): or with
1332 NVPtr pNv = NVPTR(pScrn);
1333 volatile CARD8 *ptr = crtchead ? pNv->PCIO1 : pNv->PCIO0;
1334 CARD16 reg = le16_to_cpu(*((CARD16 *)(&bios->data[offset + 1])));
1335 CARD8 and = *((CARD8 *)(&bios->data[offset + 3]));
1336 CARD8 or = *((CARD8 *)(&bios->data[offset + 4]));
1339 if (iexec->execute) {
1340 data = (VGA_RD08(ptr, reg) & and) | or;
1342 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1343 "0x%04X: CRTC REG: 0x%04X, VALUE: 0x%02X\n",
1345 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%02X\n", offset,
1346 VGA_RD08(ptr, reg));
1348 #ifdef PERFORM_WRITE
1349 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "init_index_io8 crtcreg 0x%X value 0x%X\n",reg,data);
1351 VGA_WR08(ptr, reg, data);
1357 static Bool init_sub(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1359 /* INIT_SUB opcode: 0x6B ('k')
1361 * offset (8 bit): opcode
1362 * offset + 1 (8 bit): script number
1364 * Execute script number "script number", as a subroutine
1367 uint8_t sub = bios->data[offset + 1];
1369 if (!iexec->execute)
1372 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1373 "0x%04X: EXECUTING SUB-SCRIPT %d\n", offset, sub);
1375 parse_init_table(pScrn, bios,
1376 le16_to_cpu(*((CARD16 *)(&bios->data[bios->init_script_tbls_ptr + sub * 2]))),
1379 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1380 "0x%04X: END OF SUB-SCRIPT %d\n", offset, sub);
1385 static Bool init_ram_condition(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1387 /* INIT_RAM_CONDITION opcode: 0x6D
1389 * offset (8 bit): opcode
1390 * offset + 1 (8 bit): and mask
1391 * offset + 2 (8 bit): cmpval
1393 * Test if (NV_PFB_BOOT & and mask) matches cmpval
1395 NVPtr pNv = NVPTR(pScrn);
1396 CARD8 and = *((CARD8 *) (&bios->data[offset + 1]));
1397 CARD8 cmpval = *((CARD8 *) (&bios->data[offset + 2]));
1400 if (iexec->execute) {
1401 data=(pNv->PFB[NV_PFB_BOOT/4])∧
1403 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1404 "0x%04X: CHECKING IF REGVAL: 0x%08X equals COND: 0x%08X\n",
1405 offset, data, cmpval);
1407 if (data == cmpval) {
1408 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1409 "0x%04X: CONDITION FULFILLED - CONTINUING TO EXECUTE\n",
1412 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CONDITION IS NOT FULFILLED.\n", offset);
1413 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1414 "0x%04X: ------ SKIPPING FOLLOWING COMMANDS ------\n", offset);
1415 iexec->execute = FALSE;
1421 static Bool init_nv_reg(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1423 /* INIT_NV_REG opcode: 0x6E ('n')
1425 * offset (8 bit): opcode
1426 * offset + 1 (32 bit): register
1427 * offset + 5 (32 bit): mask
1428 * offset + 9 (32 bit): data
1430 * Assign ((REGVAL("register") & "mask") | "data") to "register"
1433 uint32_t reg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 1])));
1434 uint32_t mask = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 5])));
1435 uint32_t data = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 9])));
1438 if (!iexec->execute)
1441 if (DEBUGLEVEL >= 6)
1442 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1443 "0x%04X: Reg: 0x%08X, Mask: 0x%08X, Data: 0x%08X\n",
1444 offset, reg, mask, data);
1446 nv32_rd(pScrn, reg, &value);
1448 value = (value & mask) | data;
1450 nv32_wr(pScrn, reg, value);
1455 static Bool init_macro(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1457 /* INIT_MACRO opcode: 0x6F ('o')
1459 * offset (8 bit): opcode
1460 * offset + 1 (8 bit): macro number
1462 * Look up macro index "macro number" in the macro index table.
1463 * The macro index table entry has 1 byte for the index in the macro table,
1464 * and 1 byte for the number of times to repeat the macro.
1465 * The macro table entry has 4 bytes for the register address and
1466 * 4 bytes for the value to write to that register
1469 uint8_t macro_index_tbl_idx = bios->data[offset + 1];
1470 uint16_t tmp = bios->macro_index_tbl_ptr + (macro_index_tbl_idx * MACRO_INDEX_SIZE);
1471 uint8_t macro_tbl_idx = bios->data[tmp];
1472 uint8_t count = bios->data[tmp + 1];
1476 if (!iexec->execute)
1479 if (DEBUGLEVEL >= 6)
1480 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1481 "0x%04X: Macro: 0x%02X, MacroTableIndex: 0x%02X, Count: 0x%02X\n",
1482 offset, macro_index_tbl_idx, macro_tbl_idx, count);
1484 for (i = 0; i < count; i++) {
1485 uint16_t macroentryptr = bios->macro_tbl_ptr + (macro_tbl_idx + i) * MACRO_SIZE;
1487 reg = le32_to_cpu(*((uint32_t *)(&bios->data[macroentryptr])));
1488 data = le32_to_cpu(*((uint32_t *)(&bios->data[macroentryptr + 4])));
1490 nv32_wr(pScrn, reg, data);
1496 static Bool init_done(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1498 /* INIT_DONE opcode: 0x71 ('q')
1500 * offset (8 bit): opcode
1502 * End the current script
1505 /* mild retval abuse to stop parsing this table */
1509 static Bool init_resume(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1511 /* INIT_RESUME opcode: 0x72 ('r')
1513 * offset (8 bit): opcode
1515 * End the current execute / no-execute condition
1521 iexec->execute = TRUE;;
1522 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1523 "0x%04X: ---- EXECUTING FOLLOWING COMMANDS ----\n", offset);
1528 static Bool init_ram_condition2(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1530 /* INIT_RAM_CONDITION2 opcode: 0x73
1532 * offset (8 bit): opcode
1533 * offset + 1 (8 bit): and mask
1534 * offset + 2 (8 bit): cmpval
1536 * Test if (NV_EXTDEV_BOOT & and mask) matches cmpval
1538 NVPtr pNv = NVPTR(pScrn);
1539 CARD32 and = *((CARD32 *) (&bios->data[offset + 1]));
1540 CARD32 cmpval = *((CARD32 *) (&bios->data[offset + 5]));
1543 if (iexec->execute) {
1544 data=(nvReadEXTDEV(pNv, NV_PEXTDEV_BOOT))∧
1546 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1547 "0x%04X: CHECKING IF REGVAL: 0x%08X equals COND: 0x%08X\n",
1548 offset, data, cmpval);
1550 if (data == cmpval) {
1551 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1552 "0x%04X: CONDITION FULFILLED - CONTINUING TO EXECUTE\n",
1555 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CONDITION IS NOT FULFILLED.\n", offset);
1556 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1557 "0x%04X: ------ SKIPPING FOLLOWING COMMANDS ------\n", offset);
1558 iexec->execute = FALSE;
1564 static Bool init_time(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1566 /* INIT_TIME opcode: 0x74 ('t')
1568 * offset (8 bit): opcode
1569 * offset + 1 (16 bit): time
1571 * Sleep for "time" microseconds.
1574 uint16_t time = le16_to_cpu(*((uint16_t *)(&bios->data[offset + 1])));
1576 if (!iexec->execute)
1579 if (DEBUGLEVEL >= 6)
1580 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1581 "0x%04X: Sleeping for 0x%04X microseconds.\n", offset, time);
1588 static Bool init_condition(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1590 /* INIT_CONDITION opcode: 0x75 ('u')
1592 * offset (8 bit): opcode
1593 * offset + 1 (8 bit): condition number
1595 * Check condition "condition number" in the condition table.
1596 * The condition table entry has 4 bytes for the address of the
1597 * register to check, 4 bytes for a mask and 4 for a test value.
1598 * If condition not met skip subsequent opcodes until condition
1599 * is inverted (INIT_NOT), or we hit INIT_RESUME
1602 uint8_t cond = bios->data[offset + 1];
1603 uint16_t condptr = bios->condition_tbl_ptr + cond * CONDITION_SIZE;
1604 uint32_t reg = le32_to_cpu(*((uint32_t *)(&bios->data[condptr])));
1605 uint32_t mask = le32_to_cpu(*((uint32_t *)(&bios->data[condptr + 4])));
1606 uint32_t cmpval = le32_to_cpu(*((uint32_t *)(&bios->data[condptr + 8])));
1609 if (!iexec->execute)
1612 if (DEBUGLEVEL >= 6)
1613 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1614 "0x%04X: Cond: 0x%02X, Reg: 0x%08X, Mask: 0x%08X, Cmpval: 0x%08X\n",
1615 offset, cond, reg, mask, cmpval);
1617 nv32_rd(pScrn, reg, &data);
1620 if (DEBUGLEVEL >= 6)
1621 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1622 "0x%04X: Checking if 0x%08X equals 0x%08X\n",
1623 offset, data, cmpval);
1625 if (data == cmpval) {
1626 if (DEBUGLEVEL >= 6)
1627 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1628 "0x%04X: CONDITION FULFILLED - CONTINUING TO EXECUTE\n", offset);
1630 if (DEBUGLEVEL >= 6)
1631 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1632 "0x%04X: CONDITION IS NOT FULFILLED.\n", offset);
1633 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1634 "0x%04X: ------ SKIPPING FOLLOWING COMMANDS ------\n", offset);
1635 iexec->execute = FALSE;
1641 static Bool init_index_io(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1643 /* INIT_INDEX_IO opcode: 0x78 ('x')
1645 * offset (8 bit): opcode
1646 * offset + 1 (16 bit): CRTC port
1647 * offset + 3 (8 bit): CRTC index
1648 * offset + 4 (8 bit): mask
1649 * offset + 5 (8 bit): data
1651 * Read value at index "CRTC index" on "CRTC port", AND with "mask", OR with "data", write-back
1654 uint16_t crtcport = le16_to_cpu(*((uint16_t *)(&bios->data[offset + 1])));
1655 uint8_t crtcindex = bios->data[offset + 3];
1656 uint8_t mask = bios->data[offset + 4];
1657 uint8_t data = bios->data[offset + 5];
1660 if (!iexec->execute)
1663 if (DEBUGLEVEL >= 6)
1664 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1665 "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, Data: 0x%02X\n",
1666 offset, crtcport, crtcindex, mask, data);
1668 nv_port_rd(pScrn, crtcport, crtcindex, &value);
1669 value = (value & mask) | data;
1670 nv_port_wr(pScrn, crtcport, crtcindex, value);
1675 static Bool init_pll(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1677 /* INIT_PLL opcode: 0x79 ('y')
1679 * offset (8 bit): opcode
1680 * offset + 1 (32 bit): register
1681 * offset + 5 (16 bit): freq
1683 * Set PLL register "register" to coefficients for frequency (10kHz) "freq"
1686 uint32_t reg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 1])));
1687 uint16_t freq = le16_to_cpu(*((uint16_t *)(&bios->data[offset + 5])));
1689 if (!iexec->execute)
1692 if (DEBUGLEVEL >= 6)
1693 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1694 "0x%04X: Reg: 0x%04X, Freq: %d0kHz\n",
1697 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
1702 configval = 0x00011F05;
1709 static Bool init_zm_reg(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1711 /* INIT_ZM_REG opcode: 0x7A ('z')
1713 * offset (8 bit): opcode
1714 * offset + 1 (32 bit): register
1715 * offset + 5 (32 bit): value
1717 * Assign "value" to "register"
1720 uint32_t reg = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 1])));
1721 uint32_t value = le32_to_cpu(*((uint32_t *)(&bios->data[offset + 5])));
1723 if (!iexec->execute)
1726 nv32_wr(pScrn, reg, value);
1731 static init_tbl_entry_t itbl_entry[] = {
1732 /* command name , id , length , offset , mult , command handler */
1733 { "INIT_PROG" , 0x31, 15 , 10 , 4 , init_prog },
1734 { "INIT_IO_RESTRICT_PROG" , 0x32, 11 , 6 , 4 , init_io_restrict_prog },
1735 { "INIT_REPEAT" , 0x33, 2 , 0 , 0 , init_repeat },
1736 { "INIT_IO_RESTRICT_PLL" , 0x34, 12 , 7 , 2 , init_io_restrict_pll },
1737 { "INIT_END_REPEAT" , 0x36, 1 , 0 , 0 , init_end_repeat },
1738 { "INIT_COPY" , 0x37, 11 , 0 , 0 , init_copy },
1739 { "INIT_NOT" , 0x38, 1 , 0 , 0 , init_not },
1740 { "INIT_IO_FLAG_CONDITION" , 0x39, 2 , 0 , 0 , init_io_flag_condition },
1741 { "INIT_INDEX_ADDRESS_LATCHED" , 0x49, 18 , 17 , 2 , init_idx_addr_latched },
1742 { "INIT_IO_RESTRICT_PLL2" , 0x4A, 11 , 6 , 4 , init_io_restrict_pll2 },
1743 { "INIT_PLL2" , 0x4B, 9 , 0 , 0 , init_pll2 },
1744 /* { "INIT_I2C_BYTE" , 0x4C, x , x , x , init_i2c_byte }, */
1745 /* { "INIT_ZM_I2C_BYTE" , 0x4D, x , x , x , init_zm_i2c_byte }, */
1746 /* { "INIT_ZM_I2C" , 0x4E, x , x , x , init_zm_i2c }, */
1747 { "INIT_50" , 0x50, 3 , 2 , 2 , init_50 },
1748 { "INIT_CR_INDEX_ADDRESS_LATCHED" , 0x51, 5 , 4 , 1 , init_cr_idx_adr_latch },
1749 { "INIT_CR" , 0x52, 4 , 0 , 0 , init_cr },
1750 { "INIT_ZM_CR" , 0x53, 3 , 0 , 0 , init_zm_cr },
1751 { "INIT_ZM_CR_GROUP" , 0x54, 2 , 1 , 2 , init_zm_cr_group },
1752 { "INIT_CONDITION_TIME" , 0x56, 3 , 0 , 0 , init_condition_time },
1753 { "INIT_ZM_REG_SEQUENCE" , 0x58, 6 , 5 , 4 , init_zm_reg_sequence },
1754 { "INIT_INDIRECT_REG" , 0x5A, 7 , 0 , 0 , init_indirect_reg },
1755 { "INIT_SUB_DIRECT" , 0x5B, 3 , 0 , 0 , init_sub_direct },
1756 { "INIT_COPY_NV_REG" , 0x5F, 22 , 0 , 0 , init_copy_nv_reg },
1757 { "INIT_ZM_INDEX_IO" , 0x62, 5 , 0 , 0 , init_zm_index_io },
1758 { "INIT_COMPUTE_MEM" , 0x63, 1 , 0 , 0 , init_compute_mem },
1759 { "INIT_RESET" , 0x65, 13 , 0 , 0 , init_reset },
1760 /* { "INIT_NEXT" , 0x66, x , x , x , init_next }, */
1761 /* { "INIT_NEXT" , 0x67, x , x , x , init_next }, */
1762 /* { "INIT_NEXT" , 0x68, x , x , x , init_next }, */
1763 { "INIT_INDEX_IO8" , 0x69, 5 , 0 , 0 , init_index_io8 },
1764 { "INIT_SUB" , 0x6B, 2 , 0 , 0 , init_sub },
1765 { "INIT_RAM_CONDITION" , 0x6D, 3 , 0 , 0 , init_ram_condition },
1766 { "INIT_NV_REG" , 0x6E, 13 , 0 , 0 , init_nv_reg },
1767 { "INIT_MACRO" , 0x6F, 2 , 0 , 0 , init_macro },
1768 { "INIT_DONE" , 0x71, 1 , 0 , 0 , init_done },
1769 { "INIT_RESUME" , 0x72, 1 , 0 , 0 , init_resume },
1770 { "INIT_RAM_CONDITION2" , 0x73, 9 , 0 , 0 , init_ram_condition2 },
1771 { "INIT_TIME" , 0x74, 3 , 0 , 0 , init_time },
1772 { "INIT_CONDITION" , 0x75, 2 , 0 , 0 , init_condition },
1773 /* { "INIT_IO_CONDITION" , 0x76, x , x , x , init_io_condition }, */
1774 { "INIT_INDEX_IO" , 0x78, 6 , 0 , 0 , init_index_io },
1775 { "INIT_PLL" , 0x79, 7 , 0 , 0 , init_pll },
1776 { "INIT_ZM_REG" , 0x7A, 9 , 0 , 0 , init_zm_reg },
1777 /* { "INIT_RAM_RESTRICT_ZM_REG_GROUP" , 0x8F, x , x , x , init_ram_restrict_zm_reg_group }, */
1778 /* { "INIT_COPY_ZM_REG" , 0x90, x , x , x , init_copy_zm_reg }, */
1779 /* { "INIT_ZM_REG_GROUP_ADDRESS_LATCHED" , 0x91, x , x , x , init_zm_reg_group_addr_latched }, */
1780 /* { "INIT_RESERVED" , 0x92, x , x , x , init_reserved }, */
1781 { 0 , 0 , 0 , 0 , 0 , 0 }
1784 static unsigned int get_init_table_entry_length(bios_t *bios, unsigned int offset, int i)
1786 /* Calculates the length of a given init table entry. */
1787 return itbl_entry[i].length + bios->data[offset + itbl_entry[i].length_offset]*itbl_entry[i].length_multiplier;
1790 static void parse_init_table(ScrnInfoPtr pScrn, bios_t *bios, unsigned int offset, init_exec_t *iexec)
1792 /* Parses all commands in a init table. */
1794 /* We start out executing all commands found in the
1795 * init table. Some op codes may change the status
1796 * of this variable to SKIP, which will cause
1797 * the following op codes to perform no operation until
1798 * the value is changed back to EXECUTE.
1804 /* Loop until INIT_DONE causes us to break out of the loop
1805 * (or until offset > bios length just in case... )
1806 * (and no more than 10000 iterations just in case... ) */
1807 while ((offset < bios->length) && (count++ < 10000)) {
1808 id = bios->data[offset];
1810 /* Find matching id in itbl_entry */
1811 for (i = 0; itbl_entry[i].name && (itbl_entry[i].id != id); i++)
1814 if (itbl_entry[i].name) {
1815 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ (0x%02X) - %s ]\n",
1816 offset, itbl_entry[i].id, itbl_entry[i].name);
1818 /* execute eventual command handler */
1819 if (itbl_entry[i].handler)
1820 if (!(*itbl_entry[i].handler)(pScrn, bios, offset, iexec))
1823 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1824 "0x%04X: Init table command not found: 0x%02X\n", offset, id);
1828 /* Add the offset of the current command including all data
1829 * of that command. The offset will then be pointing on the
1832 offset += get_init_table_entry_length(bios, offset, i);
1836 void parse_init_tables(ScrnInfoPtr pScrn, bios_t *bios)
1838 /* Loops and calls parse_init_table() for each present table. */
1842 init_exec_t iexec = {TRUE, FALSE};
1844 while ((table = le16_to_cpu(*((uint16_t *)(&bios->data[bios->init_script_tbls_ptr + i]))))) {
1846 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: Parsing init table %d\n",
1849 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1850 "0x%04X: ------ EXECUTING FOLLOWING COMMANDS ------\n", table);
1852 parse_init_table(pScrn, bios, table, &iexec);
1857 static void parse_fp_tables(ScrnInfoPtr pScrn, bios_t *bios)
1859 NVPtr pNv = NVPTR(pScrn);
1860 unsigned int fpstrapping;
1861 uint8_t *fptable, *fpxlatetable;
1862 /* uint8_t *lvdsmanufacturertable, *fpxlatemanufacturertable;*/
1863 unsigned int fpindex;/* lvdsmanufacturerindex;*/
1864 uint8_t fptable_ver, headerlen = 0, recordlen = 44;
1866 DisplayModePtr mode;
1868 fpstrapping = (nvReadEXTDEV(pNv, NV_PEXTDEV_BOOT) >> 16) & 0xf;
1870 if (bios->fptablepointer == 0x0) {
1871 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1872 "Pointer to flat panel table invalid\n");
1876 fptable = &bios->data[bios->fptablepointer];
1878 fptable_ver = fptable[0];
1880 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1881 "Found flat panel mode table revision %d.%d\n",
1882 fptable_ver >> 4, fptable_ver & 0xf);
1884 switch (fptable_ver) {
1885 /* PINS version 0x5.0x11 BIOSen have version 1 like tables, but no version field,
1886 * and miss one of the spread spectrum/PWM bytes.
1887 * This could affect early GF2Go parts (not seen any appropriate ROMs though).
1888 * Here we assume that a version of 0x05 matches this case (combining with a
1889 * PINS version check would be better), as the common case for the panel type
1890 * field is 0x0005, and that is in fact what we are reading the first byte of. */
1891 case 0x05: /* some NV10, 11, 15, 16 */
1892 /* note that in this version the lvdsmanufacturertable is not defined */
1896 case 0x10: /* some NV15/16, and NV11+ */
1899 if (bios->fpxlatetableptr == 0x0) {
1900 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1901 "Pointer to flat panel translation table invalid\n");
1904 fpxlatetable = &bios->data[bios->fpxlatetableptr];
1906 lvdsmanufacturertable = &bios->data[bios->lvdsmanufacturerpointer];
1907 fpxlatemanufacturertable = &bios->data[bios->fpxlatemanufacturertableptr];*/
1909 fpindex = fpxlatetable[fpstrapping];
1911 lvdsmanufacturerindex = fpxlatemanufacturertable[fpstrapping]; */
1913 if (fpindex > 0xf) {
1914 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1915 "Bad flat panel table index\n");
1919 case 0x20: /* NV40+ */
1920 headerlen = fptable[1];
1921 recordlen = fptable[2]; // check this, or hardcode as 0x20
1922 /* may be the wrong test, if there's a translation table
1923 if (fpstrapping > fptable[3]) {
1924 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1925 "Flat panel strapping number too high\n");
1929 /* I don't know where the index for the table comes from in v2.0, so bail
1932 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1933 "FP Table revision not currently supported\n");
1937 if (!(mode = xcalloc(1, sizeof(DisplayModeRec))))
1940 int modeofs = headerlen + recordlen * fpindex + ofs;
1941 mode->Clock = le16_to_cpu(*(uint16_t *)&fptable[modeofs]) * 10;
1942 mode->HDisplay = le16_to_cpu(*(uint16_t *)&fptable[modeofs + 2]);
1943 mode->HSyncStart = le16_to_cpu(*(uint16_t *)&fptable[modeofs + 10] + 1);
1944 mode->HSyncEnd = le16_to_cpu(*(uint16_t *)&fptable[modeofs + 12] + 1);
1945 mode->HTotal = le16_to_cpu(*(uint16_t *)&fptable[modeofs + 14] + 1);
1946 mode->VDisplay = le16_to_cpu(*(uint16_t *)&fptable[modeofs + 16]);
1947 mode->VSyncStart = le16_to_cpu(*(uint16_t *)&fptable[modeofs + 24] + 1);
1948 mode->VSyncEnd = le16_to_cpu(*(uint16_t *)&fptable[modeofs + 26] + 1);
1949 mode->VTotal = le16_to_cpu(*(uint16_t *)&fptable[modeofs + 28] + 1);
1950 mode->Flags |= (fptable[modeofs + 30] & 0x10) ? V_PHSYNC : V_NHSYNC;
1951 mode->Flags |= (fptable[modeofs + 30] & 0x1) ? V_PVSYNC : V_NVSYNC;
1954 * bytes 1-2 are "panel type", including bits on whether Colour/mono, single/dual link, and type (TFT etc.)
1955 * bytes 3-6 are bits per colour in RGBX
1957 * 13-14 is HValid Start
1958 * 15-16 is HValid End
1959 * bytes 38-39 relate to spread spectrum settings
1960 * bytes 40-43 are something to do with PWM */
1962 mode->prev = mode->next = NULL;
1963 mode->status = MODE_OK;
1964 mode->type = M_T_DRIVER | M_T_PREFERRED;
1965 xf86SetModeDefaultName(mode);
1967 // if (pNv->debug_modes) { this should exist
1968 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1969 "Found flat panel mode in BIOS tables:\n");
1970 xf86PrintModeline(pScrn->scrnIndex, mode);
1973 pNv->fp_native_mode = mode;
1976 static void parse_t_table(ScrnInfoPtr pScrn, bios_t *bios, uint16_t ttableptr)
1978 uint8_t headerlen = 0;
1980 init_exec_t iexec = {TRUE, FALSE};
1982 if (ttableptr == 0x0) {
1983 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1984 "Pointer to T table invalid\n");
1988 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Found T table revision %d.%d\n",
1989 bios->data[ttableptr] >> 4, bios->data[ttableptr] & 0xf);
1991 headerlen = bios->data[ttableptr + 1];
1992 table = ttableptr + headerlen;
1994 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: Parsing T table\n", table);
1995 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1996 "0x%04X: ------ EXECUTING FOLLOWING COMMANDS ------\n", table);
1997 parse_init_table(pScrn, bios, table, &iexec);
2000 static int parse_bit_display_tbl_entry(ScrnInfoPtr pScrn, bios_t *bios, bit_entry_t *bitentry)
2003 /* Parses the flat panel table segment that the bit entry points to.
2004 * Starting at bitentry->offset:
2006 * offset + 0 (16 bits): FIXME table pointer
2007 * offset + 2 (16 bits): mode table pointer
2010 /* If it's not a laptop, you probably don't care about fptables */
2011 /* FIXME: detect mobile BIOS? */
2013 NVPtr pNv = NVPTR(pScrn);
2018 if (bitentry->length != 4) {
2019 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2020 "Do not understand BIT display table entry.\n");
2024 table = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset])));
2025 bios->fptablepointer = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 2])));
2027 parse_fp_tables(pScrn, bios);
2032 static unsigned int parse_bit_init_tbl_entry(ScrnInfoPtr pScrn, bios_t *bios, bit_entry_t *bitentry)
2034 /* Parses the init table segment that the bit entry points to.
2035 * Starting at bitentry->offset:
2037 * offset + 0 (16 bits): init script tables pointer
2038 * offset + 2 (16 bits): macro index table pointer
2039 * offset + 4 (16 bits): macro table pointer
2040 * offset + 6 (16 bits): condition table pointer
2041 * offset + 8 (16 bits): io condition table pointer
2042 * offset + 10 (16 bits): io flag condition table pointer
2043 * offset + 12 (16 bits): init function table pointer
2046 * * Are 'I' bit entries always of length 0xE?
2050 if (bitentry->length < 12) {
2051 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2052 "Unable to recognize BIT init table entry.\n");
2056 bios->init_script_tbls_ptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset])));
2057 bios->macro_index_tbl_ptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 2])));
2058 bios->macro_tbl_ptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 4])));
2059 bios->condition_tbl_ptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 6])));
2060 bios->io_condition_tbl_ptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 8])));
2061 bios->io_flag_condition_tbl_ptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 10])));
2062 bios->init_function_tbl_ptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 12])));
2064 parse_init_tables(pScrn, bios);
2069 static int parse_bit_t_tbl_entry(ScrnInfoPtr pScrn, bios_t *bios, bit_entry_t *bitentry)
2071 /* Parses the pointer to the T table
2073 * Starting at bitentry->offset:
2075 * offset + 0 (16 bits): T table pointer
2080 if (bitentry->length != 2) {
2081 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2082 "Do not understand BIT T table entry.\n");
2086 ttable = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset])));
2088 parse_t_table(pScrn, bios, ttable);
2093 static unsigned int parse_bmp_table_pointers(ScrnInfoPtr pScrn, bios_t *bios, bit_entry_t *bitentry)
2095 /* Parse the pointers for useful tables in the BMP structure, starting at
2096 * offset 75 from the ..NV. signature.
2098 * First 7 pointers as for parse_bit_init_tbl_entry
2100 * offset + 30: flat panel timings table pointer
2101 * offset + 32: flat panel strapping translation table pointer
2102 * offset + 42: LVDS manufacturer panel config table pointer
2103 * offset + 44: LVDS manufacturer strapping translation table pointer
2106 NVPtr pNv = NVPTR(pScrn);
2108 if (!parse_bit_init_tbl_entry(pScrn, bios, bitentry))
2111 /* If it's not a laptop, you probably don't care about fptables */
2112 /* FIXME: detect mobile BIOS? */
2116 if (bitentry->length > 33) {
2117 bios->fptablepointer = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 30])));
2118 bios->fpxlatetableptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 32])));
2120 if (bitentry->length > 45) {
2121 bios->lvdsmanufacturerpointer = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 42])));
2122 bios->fpxlatemanufacturertableptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 44])));
2125 parse_fp_tables(pScrn, bios);
2130 static void parse_bit_structure(ScrnInfoPtr pScrn, bios_t *bios, unsigned int offset)
2132 bit_entry_t *bitentry;
2136 bitentry = (bit_entry_t *) &bios->data[offset];
2138 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2139 "0x%04X: Found BIT command with id 0x%02X\n",
2140 offset, bitentry->id[0]);
2142 switch (bitentry->id[0]) {
2144 /* id[0] = 0 and id[1] = 0 ==> end of BIT struture */
2145 if (bitentry->id[1] == 0)
2149 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2150 "0x%04X: Found flat panel display table entry in BIT structure.\n", offset);
2151 parse_bit_display_tbl_entry(pScrn, bios, bitentry);
2154 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2155 "0x%04X: Found init table entry in BIT structure.\n", offset);
2156 parse_bit_init_tbl_entry(pScrn, bios, bitentry);
2159 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2160 "0x%04X: Found T table entry in BIT structure.\n", offset);
2161 parse_bit_t_tbl_entry(pScrn, bios, bitentry);
2165 /* TODO: What kind of information does the other BIT entrys point to?
2166 * 'P' entry is probably performance tables, but there are
2167 * quite a few others...
2171 offset += sizeof(bit_entry_t);
2175 static void parse_pins_structure(ScrnInfoPtr pScrn, bios_t *bios, unsigned int offset)
2177 int pins_version_major=bios->data[offset+5];
2178 int pins_version_minor=bios->data[offset+6];
2179 int init1 = bios->data[offset + 18] + (bios->data[offset + 19] * 256);
2180 int init2 = bios->data[offset + 20] + (bios->data[offset + 21] * 256);
2181 int init_size = bios->data[offset + 22] + (bios->data[offset + 23] * 256) + 1;
2184 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PINS version %d.%d\n",
2185 pins_version_major, pins_version_minor);
2188 if (nv_cksum(bios->data + offset, 8)) {
2189 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "bad PINS checksum\n");
2193 switch (pins_version_major) {
2195 ram_tab = init1-0x0010;
2200 ram_tab = bios->data[offset + 24] + (bios->data[offset + 25] * 256);
2206 if ((pins_version_major==5)&&(pins_version_minor>=6)) {
2207 /* VCO range info */
2210 if ((pins_version_major==5)&&(pins_version_minor>=16)) {
2211 bit_entry_t bitentry;
2213 if (pins_version_minor == 0x10)
2214 bitentry.length = 12; /* I've not seen this version, so be "long enough" */
2215 else if (pins_version_minor < 0x14)
2216 bitentry.length = 34;
2218 bitentry.length = 48; /* versions after 0x14 are longer,
2219 but extra contents unneeded ATM */
2221 bitentry.offset = offset + 75;
2222 parse_bmp_table_pointers(pScrn, bios, &bitentry);
2224 /* TODO type1 script */
2228 static unsigned int findstr(bios_t* bios, unsigned char *str, int len)
2232 for (i = 2; i <= (bios->length - len); i++)
2233 if (strncmp((char *)&bios->data[i], (char *)str, len) == 0)
2239 static Bool parse_dcb_entry(uint8_t dcb_version, uint32_t conn, uint32_t conf, struct dcb_entry *entry)
2241 if (dcb_version >= 0x20) {
2242 entry->type = conn & 0xf;
2243 entry->i2c_index = (conn >> 4) & 0xf;
2244 entry->head = (conn >> 8) & 0xf;
2245 entry->bus = (conn >> 16) & 0xf;
2246 entry->location = (conn >> 20) & 0xf;
2247 entry->or = (conn >> 24) & 0xf;
2248 if ((1 << ffs(entry->or)) * 3 == entry->or)
2249 entry->duallink = TRUE;
2251 entry->duallink = FALSE;
2252 } else if (dcb_version >= 0x14 ) {
2253 if (conn != 0xf0003f00) {
2254 ErrorF("Unknown DCB 1.4 entry, please report\n");
2257 /* safe defaults for a crt */
2259 entry->i2c_index = 0;
2262 entry->location = 0;
2264 entry->duallink = FALSE;
2266 // 1.2 needs more loving
2269 entry->i2c_index = 0;
2272 entry->location = 0;
2274 entry->duallink = FALSE;
2281 read_dcb_i2c_table(ScrnInfoPtr pScrn, bios_t *bios, uint8_t dcb_version, uint16_t i2ctabptr)
2283 NVPtr pNv = NVPTR(pScrn);
2285 uint8_t headerlen = 0;
2287 int recordoffset = 0, rdofs = 1, wrofs = 0;
2290 i2c_entries = MAX_NUM_DCB_ENTRIES;
2291 memset(pNv->dcb_table.i2c_read, 0, sizeof(pNv->dcb_table.i2c_read));
2292 memset(pNv->dcb_table.i2c_write, 0, sizeof(pNv->dcb_table.i2c_write));
2294 i2ctable = &bios->data[i2ctabptr];
2296 if (dcb_version >= 0x30) {
2297 if (i2ctable[0] != dcb_version) { /* necessary? */
2298 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2299 "DCB I2C table version mismatch (%02X vs %02X)\n",
2300 i2ctable[0], dcb_version);
2303 headerlen = i2ctable[1];
2304 i2c_entries = i2ctable[2];
2305 if (i2ctable[0] >= 0x40) {
2306 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2307 "G80 DCB I2C table detected, arrgh\n"); /* they're plain weird */
2311 /* it's your own fault if you call this function on a DCB 1.1 BIOS */
2312 if (dcb_version < 0x14) {
2318 for (i = 0; i < i2c_entries; i++) {
2319 if (i2ctable[headerlen + 4 * i + 3] != 0xff) {
2320 pNv->dcb_table.i2c_read[i] = i2ctable[headerlen + recordoffset + rdofs + 4 * i];
2321 pNv->dcb_table.i2c_write[i] = i2ctable[headerlen + recordoffset + wrofs + 4 * i];
2326 static unsigned int parse_dcb_table(ScrnInfoPtr pScrn, bios_t *bios)
2328 NVPtr pNv = NVPTR(pScrn);
2329 uint16_t dcbptr, i2ctabptr = 0;
2331 uint8_t dcb_version, headerlen = 0x4, entries = MAX_NUM_DCB_ENTRIES;
2332 Bool configblock = TRUE;
2333 int recordlength = 8, confofs = 4;
2336 pNv->dcb_table.entries = 0;
2338 /* get the offset from 0x36 */
2339 dcbptr = le16_to_cpu(*(uint16_t *)&bios->data[0x36]);
2341 if (dcbptr == 0x0) {
2342 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2343 "No Display Configuration Block pointer found\n");
2347 dcbtable = &bios->data[dcbptr];
2349 /* get DCB version */
2350 dcb_version = dcbtable[0];
2351 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2352 "Display Configuration Block version %d.%d found\n",
2353 dcb_version >> 4, dcb_version & 0xf);
2355 if (dcb_version >= 0x20) { /* NV17+ */
2358 if (dcb_version >= 0x30) { /* NV40+ */
2359 headerlen = dcbtable[1];
2360 entries = dcbtable[2];
2361 i2ctabptr = le16_to_cpu(*(uint16_t *)&dcbtable[4]);
2362 sig = le32_to_cpu(*(uint32_t *)&dcbtable[6]);
2364 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2365 "DCB header length %02X, with %02X possible entries\n",
2366 headerlen, entries);
2368 /* dcb_block_count = *(dcbtable[1]); */
2369 i2ctabptr = le16_to_cpu(*(uint16_t *)&dcbtable[2]);
2370 sig = le32_to_cpu(*(uint32_t *)&dcbtable[4]);
2374 if (sig != 0x4edcbdcb) {
2375 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2376 "Bad Display Configuration Block signature (%08X)\n", sig);
2379 } else if (dcb_version >= 0x14) { /* some NV15/16, and NV11+ */
2383 strncpy(sig, (char *)&dcbtable[-7], 7);
2384 /* dcb_block_count = *(dcbtable[1]); */
2385 i2ctabptr = le16_to_cpu(*(uint16_t *)&dcbtable[2]);
2389 if (strcmp(sig, "DEV_REC")) {
2390 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2391 "Bad Display Configuration Block signature (%s)\n", sig);
2394 } else if (dcb_version >= 0x12) { /* some NV6/10, and NV15+ */
2395 /* dcb_block_count = *(dcbtable[1]); */
2396 i2ctabptr = le16_to_cpu(*(uint16_t *)&dcbtable[2]);
2397 configblock = FALSE;
2398 } else { /* NV5+, maybe NV4 */
2399 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2400 "Structure of Display Configuration Blocks prior to version 1.2 unknown\n");
2404 if (entries >= MAX_NUM_DCB_ENTRIES)
2405 entries = MAX_NUM_DCB_ENTRIES;
2407 for (i = 0; i < entries; i++) {
2408 uint32_t connection, config = 0;
2410 connection = le32_to_cpu(*(uint32_t *)&dcbtable[headerlen + recordlength * i]);
2412 config = le32_to_cpu(*(uint32_t *)&dcbtable[headerlen + confofs + recordlength * i]);
2414 /* Should we allow discontinuous DCBs? Certainly DCB I2C tables
2415 * can be discontinuous */
2416 if ((connection & 0x0000000f) == 0x0000000f) /* end of records */
2419 ErrorF("Raw DCB entry %d: %08x %08x\n", i, connection, config);
2420 if (!parse_dcb_entry(dcb_version, connection, config, &pNv->dcb_table.entry[i]))
2423 pNv->dcb_table.entries = i;
2425 read_dcb_i2c_table(pScrn, bios, dcb_version, i2ctabptr);
2427 return pNv->dcb_table.entries;
2430 unsigned int NVParseBios(ScrnInfoPtr pScrn)
2432 unsigned int bit_offset;
2435 bios.fptablepointer = 0;
2436 uint8_t nv_signature[]={0xff,0x7f,'N','V',0x0};
2437 uint8_t bit_signature[]={'B','I','T'};
2441 pNv->dcb_table.entries = 0;
2442 pNv->fp_native_mode = NULL;
2444 pNv->VBIOS = xalloc(64 * 1024);
2445 if (!NVShadowVBIOS(pScrn, pNv->VBIOS)) {
2446 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2447 "No valid BIOS image found.\n");
2451 bios.data = (uint8_t *)pNv->VBIOS;
2452 bios.length = bios.data[2] * 512;
2453 if (bios.length > NV_PROM_SIZE)
2454 bios.length = NV_PROM_SIZE;
2456 /* parse Display Configuration Block (DCB) table */
2457 if (parse_dcb_table(pScrn, &bios))
2458 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2459 "Found %d entries in DCB.\n", pNv->dcb_table.entries);
2461 /* check for known signatures */
2462 if ((bit_offset = findstr(&bios, bit_signature, sizeof(bit_signature)))) {
2463 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIT signature found.\n");
2464 parse_bit_structure(pScrn, &bios, bit_offset + 4);
2465 } else if ((bit_offset = findstr(&bios, nv_signature, sizeof(nv_signature)))) {
2466 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV signature found.\n");
2467 parse_pins_structure(pScrn, &bios, bit_offset);
2469 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2470 "No known script signature found.\n");