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 /*#define PERFORM_WRITE*/
43 uint16_t init_script_tbls_ptr;
44 uint16_t macro_index_tbl_ptr;
45 uint16_t macro_tbl_ptr;
46 uint16_t condition_tbl_ptr;
47 uint16_t io_condition_tbl_ptr;
48 uint16_t io_flag_condition_tbl_ptr;
49 uint16_t init_function_tbl_ptr;
51 uint16_t fptablepointer;
52 uint16_t fpxlatetableptr;
53 uint16_t lvdsmanufacturerpointer;
54 uint16_t fpxlatemanufacturertableptr;
57 static Bool nv_cksum(const uint8_t *data, unsigned int offset, unsigned int length)
59 /* there's a few checksums in the BIOS, so here's a generic checking function */
63 for (i = 0; i < length; i++)
64 sum += data[offset + i];
72 static Bool NVValidVBIOS(ScrnInfoPtr pScrn, const uint8_t *data)
74 /* check for BIOS signature */
75 if (!(data[0] == 0x55 && data[1] == 0xAA)) {
76 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
77 "... BIOS signature not found\n");
81 if (nv_cksum(data, 0, data[2] * 512)) {
82 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
83 "... BIOS checksum invalid\n");
84 /* probably ought to set a do_not_execute flag for table parsing here,
85 * assuming most BIOSen are valid */
87 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "... appears to be valid\n");
92 static void NVShadowVBIOS_PROM(ScrnInfoPtr pScrn, uint8_t *data)
94 NVPtr pNv = NVPTR(pScrn);
97 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
98 "Attempting to locate BIOS image in PROM\n");
100 /* enable ROM access */
101 nvWriteMC(pNv, 0x1850, 0x0);
102 for (i = 0; i < NV_PROM_SIZE; i++) {
103 /* according to nvclock, we need that to work around a 6600GT/6800LE bug */
104 data[i] = pNv->PROM[i];
105 data[i] = pNv->PROM[i];
106 data[i] = pNv->PROM[i];
107 data[i] = pNv->PROM[i];
108 data[i] = pNv->PROM[i];
110 /* disable ROM access */
111 nvWriteMC(pNv, 0x1850, 0x1);
114 #define NV_PRAMIN_ROM_OFFSET 0x00700000
116 static void NVShadowVBIOS_PRAMIN(ScrnInfoPtr pScrn, uint32_t *data)
118 NVPtr pNv = NVPTR(pScrn);
119 const uint32_t *pramin = (void*)&pNv->REGS[NV_PRAMIN_ROM_OFFSET/4];
120 uint32_t old_bar0_pramin = 0;
122 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
123 "Attempting to locate BIOS image in PRAMIN\n");
125 if (pNv->Architecture >= NV_ARCH_50) {
128 vbios_vram = (pNv->REGS[0x619f04/4] & ~0xff) << 8;
130 vbios_vram = pNv->REGS[0x1700/4] << 16;
131 vbios_vram += 0xf0000;
134 old_bar0_pramin = pNv->REGS[0x1700/4];
135 pNv->REGS[0x1700/4] = vbios_vram >> 16;
138 memcpy(data, pramin, NV_PROM_SIZE);
140 if (pNv->Architecture >= NV_ARCH_50) {
141 pNv->REGS[0x1700/4] = old_bar0_pramin;
145 static Bool NVShadowVBIOS(ScrnInfoPtr pScrn, uint32_t *data)
147 NVShadowVBIOS_PROM(pScrn, (uint8_t *)data);
148 if (NVValidVBIOS(pScrn, (uint8_t *)data))
151 NVShadowVBIOS_PRAMIN(pScrn, data);
152 if (NVValidVBIOS(pScrn, (uint8_t *)data))
163 int length_multiplier;
164 Bool (*handler)(ScrnInfoPtr pScrn, bios_t *, uint16_t, init_exec_t *);
173 static void parse_init_table(ScrnInfoPtr pScrn, bios_t *bios, unsigned int offset, init_exec_t *iexec);
175 #define MACRO_INDEX_SIZE 2
177 #define CONDITION_SIZE 12
178 #define IO_FLAG_CONDITION_SIZE 9
186 static int nv_valid_reg(uint32_t reg)
188 #define WITHIN(x,y,z) ((x>=y)&&(x<y+z))
189 if (WITHIN(reg,NV_PRAMIN_OFFSET,NV_PRAMIN_SIZE))
191 if (WITHIN(reg,NV_PCRTC0_OFFSET,NV_PCRTC0_SIZE))
193 if (WITHIN(reg,NV_PRAMDAC0_OFFSET,NV_PRAMDAC0_SIZE))
195 if (WITHIN(reg,NV_PFB_OFFSET,NV_PFB_SIZE))
197 if (WITHIN(reg,NV_PFIFO_OFFSET,NV_PFIFO_SIZE))
199 if (WITHIN(reg,NV_PGRAPH_OFFSET,NV_PGRAPH_SIZE))
201 if (WITHIN(reg,NV_PEXTDEV_OFFSET,NV_PEXTDEV_SIZE))
203 if (WITHIN(reg,NV_PTIMER_OFFSET,NV_PTIMER_SIZE))
205 if (WITHIN(reg,NV_PVIDEO_OFFSET,NV_PVIDEO_SIZE))
207 if (WITHIN(reg,NV_PMC_OFFSET,NV_PMC_SIZE))
209 if (WITHIN(reg,NV_FIFO_OFFSET,NV_FIFO_SIZE))
211 if (WITHIN(reg,NV_PCIO0_OFFSET,NV_PCIO0_SIZE))
213 if (WITHIN(reg,NV_PDIO0_OFFSET,NV_PDIO0_SIZE))
215 if (WITHIN(reg,NV_PVIO_OFFSET,NV_PVIO_SIZE))
217 if (WITHIN(reg,NV_PROM_OFFSET,NV_PROM_SIZE))
219 if (WITHIN(reg,NV_PRAMIN_ROM_OFFSET,NV_PROM_SIZE))
225 static void nv32_rd(ScrnInfoPtr pScrn, uint32_t reg, uint32_t *data)
227 NVPtr pNv = NVPTR(pScrn);
229 *data = pNv->REGS[reg/4];
231 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
232 " Read: Reg: 0x%08X, Data: 0x%08X\n", reg, *data);
235 static int nv32_wr(ScrnInfoPtr pScrn, uint32_t reg, uint32_t data)
237 if (DEBUGLEVEL >= 8) {
239 nv32_rd(pScrn, reg, &tmp);
242 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
243 " Write: Reg: 0x%08X, Data: 0x%08X\n", reg, data);
244 if (!nv_valid_reg(reg)) {
245 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
246 "========= unknown reg 0x%X ==========\n", reg);
251 NVPtr pNv = NVPTR(pScrn);
252 pNv->REGS[reg/4] = data;
257 static void nv_port_rd(ScrnInfoPtr pScrn, uint16_t port, uint8_t index, uint8_t *data, int head)
259 NVPtr pNv = NVPTR(pScrn);
260 volatile uint8_t *ptr = head ? pNv->PCIO1 : pNv->PCIO0;
262 VGA_WR08(ptr, port, index);
263 *data = VGA_RD08(ptr, port + 1);
266 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
267 " Indexed read: Port: 0x%04X, Index: 0x%02X, Head: 0x%02X, Data: 0x%02X\n",
268 port, index, head, *data);
271 static void nv_port_wr(ScrnInfoPtr pScrn, uint16_t port, uint8_t index, uint8_t data, int head)
273 NVPtr pNv = NVPTR(pScrn);
274 volatile uint8_t *ptr = head ? pNv->PCIO1 : pNv->PCIO0;
276 if (DEBUGLEVEL >= 8) {
278 nv_port_rd(pScrn, port, index, &tmp, head);
281 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
282 " Indexed write: Port: 0x%04X, Index: 0x%02X, Head: 0x%02X, Data: 0x%02X\n",
283 port, index, head, data);
286 VGA_WR08(ptr, port, index);
287 VGA_WR08(ptr, port + 1, data);
291 static void nv_set_crtc_index(ScrnInfoPtr pScrn, CARD8 index)
294 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv_set_crtc_index index 0x%X\n",index);
296 NVPtr pNv = NVPTR(pScrn);
297 volatile CARD8 *ptr = pNv->cur_head ? pNv->PCIO1 : pNv->PCIO0;
298 VGA_WR08(ptr, 0x3D4, index);
302 static CARD8 nv_rd_crtc_data(ScrnInfoPtr pScrn)
304 NVPtr pNv = NVPTR(pScrn);
305 volatile CARD8 *ptr = pNv->cur_head ? pNv->PCIO1 : pNv->PCIO0;
306 return VGA_RD08(ptr, 0x3D5);
309 static void nv_wr_crtc_data(ScrnInfoPtr pScrn, CARD8 val)
312 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "nv_wr_crtc_data value 0x%X\n",val);
314 NVPtr pNv = NVPTR(pScrn);
315 volatile CARD8 *ptr = pNv->cur_head ? pNv->PCIO1 : pNv->PCIO0;
316 VGA_WR08(ptr, 0x3D5, val);
320 static Bool init_prog(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
322 /* INIT_PROG opcode: 0x31
324 * offset (8 bit): opcode
325 * offset + 1 (32 bit): reg
326 * offset + 5 (32 bit): and mask
327 * offset + 9 (8 bit): shift right
328 * offset + 10 (8 bit): number of configurations
329 * offset + 11 (32 bit): register
330 * offset + 15 (32 bit): configuration 1
333 * Starting at offset + 15 there are "number of configurations"
334 * 32 bit values. To find out which configuration value to use
335 * read "CRTC reg" on the CRTC controller with index "CRTC index"
336 * and bitwise AND this value with "and mask" and then bit shift the
337 * result "shift right" bits to the right.
338 * Assign "register" with appropriate configuration value.
341 CARD32 reg = *((CARD32 *) (&bios->data[offset + 1]));
342 CARD32 and = *((CARD32 *) (&bios->data[offset + 5]));
343 CARD8 shiftr = *((CARD8 *) (&bios->data[offset + 9]));
344 CARD8 nr = *((CARD8 *) (&bios->data[offset + 10]));
345 CARD32 reg2 = *((CARD32 *) (&bios->data[offset + 11]));
347 CARD32 configval, tmp;
349 if (iexec->execute) {
350 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: REG: 0x%04X\n", offset,
353 nv32_rd(pScrn, reg, &tmp);
354 configuration = (tmp & and) >> shiftr;
356 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CONFIGURATION TO USE: 0x%02X\n",
357 offset, configuration);
359 if (configuration <= nr) {
362 *((CARD32 *) (&bios->data[offset + 15 + configuration * 4]));
364 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: REG: 0x%08X, VALUE: 0x%08X\n", offset,
367 nv32_rd(pScrn, reg2, &tmp);
368 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%08X\n",
370 nv32_wr(pScrn, reg2, configval);
376 static Bool init_io_restrict_prog(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
378 /* INIT_IO_RESTRICT_PROG opcode: 0x32 ('2')
380 * offset (8 bit): opcode
381 * offset + 1 (16 bit): CRTC port
382 * offset + 3 (8 bit): CRTC index
383 * offset + 4 (8 bit): mask
384 * offset + 5 (8 bit): shift
385 * offset + 6 (8 bit): count
386 * offset + 7 (32 bit): register
387 * offset + 11 (32 bit): configuration 1
390 * Starting at offset + 11 there are "count" 32 bit values.
391 * To find out which value to use read index "CRTC index" on "CRTC port",
392 * AND this value with "mask" and then bit shift right "shift" bits.
393 * Read the appropriate value using this index and write to "register"
396 uint16_t crtcport = *((uint16_t *)(&bios->data[offset + 1]));
397 uint8_t crtcindex = *((uint8_t *)(&bios->data[offset + 3]));
398 uint8_t mask = *((uint8_t *)(&bios->data[offset + 4]));
399 uint8_t shift = *((uint8_t *)(&bios->data[offset + 5]));
400 uint8_t count = *((uint8_t *)(&bios->data[offset + 6]));
401 uint32_t reg = *((uint32_t *)(&bios->data[offset + 7]));
409 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
410 "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, Shift: 0x%02X, Count: 0x%02X, Reg: 0x%08X\n",
411 offset, crtcport, crtcindex, mask, shift, count, reg);
413 /* FIXME how to choose head?? */
414 nv_port_rd(pScrn, crtcport, crtcindex, &config, 0);
415 config = (config & mask) >> shift;
416 if (config > count) {
417 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
418 "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
419 offset, config, count);
423 configval = *((uint32_t *)(&bios->data[offset + 11 + config * 4]));
426 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
427 "0x%04X: Writing config %02X\n", offset, config);
429 nv32_wr(pScrn, reg, configval);
434 static Bool init_repeat(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
436 CARD8 repeats = *((CARD8 *) (&bios->data[offset + 1]));
439 if (iexec->execute) {
440 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: REPEATING FOLLOWING SEGMENT %d TIMES.\n",
443 iexec->repeat = TRUE;
445 for (i = 0; i < repeats - 1; i++)
446 parse_init_table(pScrn, bios, offset + 2, iexec);
448 iexec->repeat = FALSE;
453 static Bool init_end_repeat(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
461 static Bool init_copy(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
463 /* INIT_COPY opcode: 0x37 ('7')
465 * offset (8 bit): opcode
466 * offset + 1 (32 bit): register
467 * offset + 5 (8 bit): shift
468 * offset + 6 (8 bit): srcmask
469 * offset + 7 (16 bit): CRTC port
470 * offset + 9 (8 bit): CRTC index
471 * offset + 10 (8 bit): mask
473 * Read index "CRTC index" on "CRTC port", AND with "mask", OR with
474 * (REGVAL("register") >> "shift" & "srcmask") and write-back to CRTC port
477 uint32_t reg = *((uint32_t *)(&bios->data[offset + 1]));
478 uint8_t shift = *((uint8_t *)(&bios->data[offset + 5]));
479 uint8_t srcmask = *((uint8_t *)(&bios->data[offset + 6]));
480 uint16_t crtcport = *((uint16_t *)(&bios->data[offset + 7]));
481 uint8_t crtcindex = *((uint8_t *)(&bios->data[offset + 9]));
482 uint8_t mask = *((uint8_t *)(&bios->data[offset + 10]));
490 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
491 "0x%04X: Reg: 0x%08X, Shift: 0x%02X, SrcMask: 0x%02X, Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X\n",
492 offset, reg, shift, srcmask, crtcport, crtcindex, mask);
494 nv32_rd(pScrn, reg, &data);
499 data <<= (0x100 - shift);
503 /* FIXME how to choose head?? */
504 nv_port_rd(pScrn, crtcport, crtcindex, &crtcdata, 0);
505 crtcdata = (crtcdata & mask) | (uint8_t)data;
506 nv_port_wr(pScrn, crtcport, crtcindex, crtcdata, 0);
511 static Bool init_not(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
513 /* INIT_NOT opcode: 0x38 ('8')
515 * offset (8 bit): opcode
517 * Invert the current execute / no-execute condition (i.e. "else")
520 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
521 "0x%04X: ------ SKIPPING FOLLOWING COMMANDS ------\n", offset);
523 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
524 "0x%04X: ------ EXECUTING FOLLOWING COMMANDS ------\n", offset);
526 iexec->execute = !iexec->execute;
530 static Bool io_flag_condition(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, uint8_t cond)
532 /* The IO flag condition entry has 2 bytes for the CRTC port; 1 byte
533 * for the CRTC index; 1 byte for the mask to apply to the value
534 * retrieved from the CRTC; 1 byte for the shift right to apply to the
535 * masked CRTC value; 2 bytes for the offset to the flag array, to
536 * which the shifted value is added; 1 byte for the mask applied to the
537 * value read from the flag array; and 1 byte for the value to compare
538 * against the masked byte from the flag table.
541 uint16_t condptr = bios->io_flag_condition_tbl_ptr + cond * IO_FLAG_CONDITION_SIZE;
542 uint16_t crtcport = *((uint16_t *)(&bios->data[condptr]));
543 uint8_t crtcindex = *((uint8_t *)(&bios->data[condptr + 2]));
544 uint8_t mask = *((uint8_t *)(&bios->data[condptr + 3]));
545 uint8_t shift = *((uint8_t *)(&bios->data[condptr + 4]));
546 uint16_t flagarray = *((uint16_t *)(&bios->data[condptr + 5]));
547 uint8_t flagarraymask = *((uint8_t *)(&bios->data[condptr + 7]));
548 uint8_t cmpval = *((uint8_t *)(&bios->data[condptr + 8]));
552 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
553 "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, Shift: 0x%02X, FlagArray: 0x%04X, FAMask: 0x%02X, Cmpval: 0x%02X\n",
554 offset, crtcport, crtcindex, mask, shift, flagarray, flagarraymask, cmpval);
556 /* FIXME how to choose head?? */
557 nv_port_rd(pScrn, crtcport, crtcindex, &data, 0);
559 data = *((uint8_t *)(&bios->data[flagarray + ((data & mask) >> shift)]));
560 data &= flagarraymask;
563 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
564 "0x%04X: Checking if 0x%02X equals 0x%02X\n",
565 offset, data, cmpval);
573 static Bool init_io_flag_condition(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
575 /* INIT_IO_FLAG_CONDITION opcode: 0x39 ('9')
577 * offset (8 bit): opcode
578 * offset + 1 (8 bit): condition number
580 * Check condition "condition number" in the IO flag condition table.
581 * If condition not met skip subsequent opcodes until condition
582 * is inverted (INIT_NOT), or we hit INIT_RESUME
585 uint8_t cond = *((uint8_t *)(&bios->data[offset + 1]));
590 if (io_flag_condition(pScrn, bios, offset, cond))
591 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
592 "0x%04X: CONDITION FULFILLED - CONTINUING TO EXECUTE\n", offset);
594 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
595 "0x%04X: CONDITION IS NOT FULFILLED.\n", offset);
596 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
597 "0x%04X: ------ SKIPPING FOLLOWING COMMANDS ------\n", offset);
598 iexec->execute = FALSE;
604 static Bool init_io_restrict_pll(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
606 /* INIT_IO_RESTRICT_PLL opcode: 0x34 ('4')
608 * offset (8 bit): opcode
609 * offset + 1 (16 bit): CRTC port
610 * offset + 3 (8 bit): CRTC index
611 * offset + 4 (8 bit): mask
612 * offset + 5 (8 bit): shift
613 * offset + 6 (8 bit): IO flag condition index
614 * offset + 7 (8 bit): count
615 * offset + 8 (32 bit): register
616 * offset + 12 (16 bit): frequency 1
619 * Starting at offset + 12 there are "count" 16 bit frequencies (10kHz).
620 * Set PLL register "register" to coefficients for frequency n,
621 * selected by reading index "CRTC index" of "CRTC port" ANDed with
622 * "mask" and shifted right by "shift". If "IO flag condition index" > 0,
623 * and condition met, double frequency before setting it.
626 uint16_t crtcport = *((uint16_t *)(&bios->data[offset + 1]));
627 uint8_t crtcindex = *((uint8_t *)(&bios->data[offset + 3]));
628 uint8_t mask = *((uint8_t *)(&bios->data[offset + 4]));
629 uint8_t shift = *((uint8_t *)(&bios->data[offset + 5]));
630 int8_t io_flag_condition_idx = *((int8_t *)(&bios->data[offset + 6]));
631 uint8_t count = *((uint8_t *)(&bios->data[offset + 7]));
632 uint32_t reg = *((uint32_t *)(&bios->data[offset + 8]));
640 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
641 "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",
642 offset, crtcport, crtcindex, mask, shift, io_flag_condition_idx, count, reg);
644 /* FIXME how to choose head?? */
645 nv_port_rd(pScrn, crtcport, crtcindex, &config, 0);
646 config = (config & mask) >> shift;
647 if (config > count) {
648 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
649 "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
650 offset, config, count);
654 freq = *((uint16_t *)(&bios->data[offset + 12 + config * 2]));
656 if (io_flag_condition_idx > 0) {
657 if (io_flag_condition(pScrn, bios, offset, io_flag_condition_idx)) {
658 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
659 "0x%04X: CONDITION FULFILLED - FREQ DOUBLED\n", offset);
662 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
663 "0x%04X: CONDITION IS NOT FULFILLED. FREQ UNCHANGED\n", offset);
667 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
668 "0x%04X: Reg: 0x%08X, Config: 0x%02X, Freq: %d0kHz\n",
669 offset, reg, config, freq);
671 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
676 configval = 0x01014E07;
679 configval = 0x13030E02;
686 static Bool init_pll(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
688 /* INIT_PLL opcode: 0x79 ('y')
690 * offset (8 bit): opcode
691 * offset + 1 (32 bit): register
692 * offset + 5 (16 bit): freq
694 * Set PLL register "register" to coefficients for frequency (10kHz) "freq"
697 uint32_t reg = *((uint32_t *)(&bios->data[offset + 1]));
698 uint16_t freq = *((uint16_t *)(&bios->data[offset + 5]));
704 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
705 "0x%04X: Reg: 0x%04X, Freq: %d0kHz\n",
710 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
715 configval = 0x00011F05;
722 Bool init_idx_addr_latched(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
724 /* INIT_INDEX_ADDRESS_LATCHED opcode: 0x49 ('I')
726 * offset (8 bit): opcode
727 * offset + 1 (32 bit): register
728 * offset + 5 (32 bit): register
729 * offset + 9 (FIXME bit): FIXME
730 * offset + 17 (8 bit): count
731 * offset + 18 (8 bit): configuration 1
732 * offset + 19 (8 bit): configuration 1
738 uint32_t rega = *((uint32_t *)(&bios->data[offset + 1]));
739 uint32_t regb = *((uint32_t *)(&bios->data[offset + 5]));
740 uint8_t count = *((uint8_t *)(&bios->data[offset + 17]));
746 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
749 for (i = 0; i < count; i++) {
750 nv_set_crtc_index(pScrn, crtcindex);
752 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CRTC INDEX: %02X DATA: %02X\n", offset,
753 crtcindex, initial_index + i);
755 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%02X\n", offset,
756 nv_rd_crtc_data(pScrn));
758 nv_wr_crtc_data(pScrn, initial_index + i);
760 nv_set_crtc_index(pScrn, crtcdata);
762 data = *((CARD8 *)(&bios->data[offset + 5 + i]));
764 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CRTC INDEX: %02X DATA: %02X\n", offset,
767 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%02X\n", offset,
768 nv_rd_crtc_data(pScrn));
770 nv_wr_crtc_data(pScrn, data);
776 Bool init_cr_idx_adr_latch(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
778 CARD8 crtcindex = *((CARD8 *) (&bios->data[offset + 1]));
779 CARD8 crtcdata = *((CARD8 *) (&bios->data[offset + 2]));
780 CARD8 initial_index = *((CARD8 *) (&bios->data[offset + 3]));
781 CARD8 entries = *((CARD8 *) (&bios->data[offset + 4]));
785 if (iexec->execute) {
786 for (i = 0; i < entries; i++) {
787 nv_set_crtc_index(pScrn, crtcindex);
789 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CRTC INDEX: %02X DATA: %02X\n", offset,
790 crtcindex, initial_index + i);
792 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%02X\n", offset,
793 nv_rd_crtc_data(pScrn));
795 nv_wr_crtc_data(pScrn, initial_index + i);
797 nv_set_crtc_index(pScrn, crtcdata);
799 data = *((CARD8 *) (&bios->data[offset + 5 + i]));
801 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CRTC INDEX: %02X DATA: %02X\n", offset,
804 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%02X\n", offset,
805 nv_rd_crtc_data(pScrn));
807 nv_wr_crtc_data(pScrn, data);
813 Bool init_cr(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
815 /* XXX: IS THIS CORRECT? check the typecast .. probably wrong */
817 NVPtr pNv = NVPTR(pScrn);
818 CARD8 index = *((CARD32 *) (&bios->data[offset + 1]));
819 CARD8 and = *((CARD8 *) (&bios->data[offset + 2]));
820 CARD8 or = *((CARD8 *) (&bios->data[offset + 3]));
823 if (iexec->execute) {
824 nv_set_crtc_index(pScrn, index);
825 data = (nv_rd_crtc_data(pScrn) & and) | or;
826 /*printf("and: 0x%02x or: 0x%02x\n", and, or);*/
827 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CRTC INDEX: 0x%02X, VALUE: 0x%02X\n", offset,
830 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%02X\n", offset,
831 nv_rd_crtc_data(pScrn));
833 nv_wr_crtc_data(pScrn, data);
838 static Bool init_zm_cr(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
840 /* INIT_ZM_CR opcode: 0x53
842 * offset (8 bit): opcode
843 * offset + 1 (8 bit): CRTC index
844 * offset + 2 (8 bit): value
846 * Assign "value" to CRTC register with index "CRTC index".
849 NVPtr pNv = NVPTR(pScrn);
850 CARD8 index = *((CARD32 *) (&bios->data[offset + 1]));
851 CARD8 value = *((CARD8 *) (&bios->data[offset + 2]));
853 if (iexec->execute) {
854 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CRTC INDEX: 0x%02X, VALUE: 0x%02X\n", offset,
857 nv_set_crtc_index(pScrn, index);
859 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%02X\n", offset,
860 nv_rd_crtc_data(pScrn));
862 nv_wr_crtc_data(pScrn, value);
867 static Bool init_zm_cr_group(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
869 /* INIT_ZM_CR opcode: 0x54
871 * offset (8 bit): opcode
872 * offset + 1 (8 bit): number of groups (index, value)
873 * offset + 2 (8 bit): index 1
874 * offset + 3 (8 bit): value 1
877 * Assign "value n" to CRTC register with index "index n".
880 CARD8 nr = *((CARD8 *) (&bios->data[offset + 1]));
884 if (iexec->execute) {
885 for (i = 0; i < nr; i++) {
886 index = *((CARD8 *) (&bios->data[offset + 2 + 2 * i]));
887 value = *((CARD8 *) (&bios->data[offset + 2 + 2 * i + 1]));
889 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CRTC INDEX: 0x%02X, VALUE: 0x%02X\n", offset,
892 nv_set_crtc_index(pScrn, index);
894 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%02X\n", offset,
895 nv_rd_crtc_data(pScrn));
896 nv_wr_crtc_data(pScrn, value);
902 static Bool init_condition_time(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
904 /* My BIOS does not use this command. */
905 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
910 static Bool init_zm_reg_sequence(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
912 /* INIT_ZM_REG_SEQUENCE opcode: 0x58
914 * offset (8 bit): opcode
915 * offset + 1 (32 bit): register base
916 * offset + 5 (8 bit): nr
917 * offset + 6 (32 bit): value to assign "register base" + 4
920 * Initialzies a sequence of "nr" registers starting at "register base".
923 CARD32 reg = *((CARD32 *) (&bios->data[offset + 1]));
924 CARD32 nr = *((CARD8 *) (&bios->data[offset + 5]));
929 if (iexec->execute) {
930 for (i = 0; i < nr; i++) {
931 data = *((CARD32 *) (&bios->data[offset + 6 + i * 4]));
932 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: REG: 0x%08X, VALUE: 0x%08X\n", offset,
935 nv32_rd(pScrn, reg + i * 4, &tmp);
936 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%08X\n",
939 nv32_wr(pScrn, reg + i * 4, data);
945 static Bool init_indirect_reg(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
947 /* INIT_INDIRECT_REG opcode: 0x5A
949 * offset (8 bit): opcode
950 * offset + 1 (32 bit): register
951 * offset + 5 (16 bit): adress offset (in bios)
953 * Lookup value at offset data in the bios and write it to reg
955 NVPtr pNv = NVPTR(pScrn);
956 CARD32 reg = *((CARD32 *) (&bios->data[offset + 1]));
957 CARD32 data = *((CARD16 *) (&bios->data[offset + 5]));
958 CARD32 data2 = bios->data[data];
960 if (iexec->execute) {
961 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
962 "0x%04X: REG: 0x%04X, DATA AT: 0x%04X, VALUE IS: 0x%08X\n",
963 offset, reg, data, data2);
965 if (DEBUGLEVEL >= 6) {
967 nv32_rd(pScrn, reg, &tmpval);
968 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%08X\n", offset, tmpval);
971 nv32_wr(pScrn, reg, data2);
976 static Bool init_sub_direct(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
978 /* INIT_SUB_DIRECT opcode: 0x5B
980 * offset (8 bit): opcode
981 * offset + 1 (16 bit): subroutine offset (in bios)
983 * Calls a subroutine that will execute commands until INIT_DONE
987 CARD16 sub_offset = *((CARD16 *) (&bios->data[offset + 1]));
989 if (iexec->execute) {
990 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: EXECUTING SUB-ROUTINE AT: 0x%04X\n",
993 parse_init_table(pScrn, bios, sub_offset, iexec);
995 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: END OF SUB-ROUTINE\n", offset);
1000 static Bool init_copy_nv_reg(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1002 CARD32 srcreg = *((CARD32 *) (&bios->data[offset + 1]));
1003 CARD8 shift = *((CARD8 *) (&bios->data[offset + 5]));
1004 CARD32 and1 = *((CARD32 *) (&bios->data[offset + 6]));
1005 CARD32 xor = *((CARD32 *) (&bios->data[offset + 10]));
1006 CARD32 dstreg = *((CARD32 *) (&bios->data[offset + 14]));
1007 CARD32 and2 = *((CARD32 *) (&bios->data[offset + 18]));
1011 if (iexec->execute) {
1012 nv32_rd(pScrn, srcreg, &srcdata);
1019 srcdata = (srcdata & and1) ^ xor;
1021 nv32_rd(pScrn, dstreg, &dstdata);
1027 nv32_rd(pScrn, dstreg, &tmp);
1029 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: REG: 0x%08X, VALUE: 0x%08X\n", offset, dstreg,
1032 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%08X\n", offset, tmp);
1034 nv32_wr(pScrn, dstreg, dstdata);
1039 static Bool init_zm_index_io(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1041 /* INIT_ZM_INDEX_IO opcode: 0x62 ('b')
1043 * offset (8 bit): opcode
1044 * offset + 1 (16 bit): CRTC port
1045 * offset + 3 (8 bit): CRTC index
1046 * offset + 4 (8 bit): data
1048 * Write "data" to index "CRTC index" of "CRTC port"
1050 uint16_t crtcport = *((uint16_t *)(&bios->data[offset + 1]));
1051 uint8_t crtcindex = *((uint8_t *)(&bios->data[offset + 3]));
1052 uint8_t data = *((uint8_t *)(&bios->data[offset + 4]));
1054 if (!iexec->execute)
1057 /* FIXME how to choose head?? */
1058 nv_port_wr(pScrn, crtcport, crtcindex, data, 0);
1063 static Bool init_compute_mem(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1065 /* INIT_COMPUTE_MEM opcode: 0x63 ('c')
1067 * offset (8 bit): opcode
1072 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ NOT YET IMPLEMENTED ]\n", offset);
1074 uint16_t ramcfg = *((uint16_t *)(&bios->data[bios->ram_table_offset]));
1079 if (!iexec->execute)
1082 nv32_rd(pScrn, 0x00101000, &strapinfo);
1083 nv32_rd(pScrn, 0x00100080, &pfb_debug);
1085 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "STRAPINFO: 0x%08X\n", strapinfo);
1086 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PFB_DEBUG: 0x%08X\n", pfb_debug);
1087 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RAM CFG: 0x%04X\n", ramcfg);
1089 pfb_debug &= 0xffffffef;
1091 strapinfo &= 0x0000000f;
1092 ramcfg2 = *((uint16_t *)
1093 (&bios->data[bios->ram_table_offset + (2 * strapinfo)]));
1095 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "AFTER MANIPULATION\n");
1096 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "STRAPINFO: 0x%08X\n", strapinfo);
1097 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PFB_DEBUG: 0x%08X\n", pfb_debug);
1098 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RAM CFG2: 0x%08X\n", ramcfg2);
1104 nv32_rd(pScrn, 0x00100200, ®1);
1105 nv32_rd(pScrn, 0x0010020C, ®2);
1107 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x00100200: 0x%08X\n", reg1);
1108 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x0010020C: 0x%08X\n", reg2);
1114 #define NV_PBUS_PCI_NV_19 0x0000184C
1116 static Bool init_reset(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1118 /* INIT_RESET opcode: 0x65 ('e')
1120 * offset (8 bit): opcode
1121 * offset + 1 (32 bit): register
1122 * offset + 5 (32 bit): value1
1123 * offset + 9 (32 bit): value2
1125 * Assign "value1" to "register", then assign "value2" to "register"
1128 uint32_t reg = *((uint32_t *)(&bios->data[offset + 1]));
1129 uint32_t value1 = *((uint32_t *)(&bios->data[offset + 5]));
1130 uint32_t value2 = *((uint32_t *)(&bios->data[offset + 9]));
1133 if (!iexec->execute)
1136 if (DEBUGLEVEL >= 6)
1137 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1138 "0x%04X: Reg: 0x%08X, Value1: 0x%08X, Value2: 0x%08X\n",
1139 offset, reg, value1, value2);
1141 /* 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 */
1142 nv32_rd(pScrn, NV_PBUS_PCI_NV_19, &pci_nv_19);
1144 nv32_rd(pScrn, PCICFG(PCICFG_ROMSHADOW), &tmpval);
1145 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: PCICFG_ROMSHADOW: 0x%02X\n", offset, tmpval);
1147 nv32_wr(pScrn, NV_PBUS_PCI_NV_19, 0);
1148 nv32_wr(pScrn, reg, value1);
1149 nv32_wr(pScrn, reg, value2);
1150 nv32_wr(pScrn, NV_PBUS_PCI_NV_19, pci_nv_19);
1152 /* PCI Config space init needs to be added here. */
1153 /* if (nv32_rd(pScrn, PCICFG(PCICFG_ROMSHADOW), value1)) */
1154 /* nv32_wr(pScrn, PCICFG(PCICFG_ROMSHADOW), value1 & 0xfffffffe) */
1159 static Bool init_index_io8(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1161 /* INIT_INDEX_IO8 opcode: 0x69
1163 * offset (8 bit): opcode
1164 * offset + 1 (16 bit): CRTC reg
1165 * offset + 3 (8 bit): and mask
1166 * offset + 4 (8 bit): or with
1171 NVPtr pNv = NVPTR(pScrn);
1172 /* FIXME how to choose head?? */
1173 volatile CARD8 *ptr = pNv->cur_head ? pNv->PCIO1 : pNv->PCIO0;
1174 CARD16 reg = *((CARD16 *)(&bios->data[offset + 1]));
1175 CARD8 and = *((CARD8 *)(&bios->data[offset + 3]));
1176 CARD8 or = *((CARD8 *)(&bios->data[offset + 4]));
1179 if (iexec->execute) {
1180 data = (VGA_RD08(ptr, reg) & and) | or;
1182 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1183 "0x%04X: CRTC REG: 0x%04X, VALUE: 0x%02X\n",
1185 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CURRENT VALUE IS: 0x%02X\n", offset,
1186 VGA_RD08(ptr, reg));
1188 #ifdef PERFORM_WRITE
1189 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "init_index_io8 crtcreg 0x%X value 0x%X\n",reg,data);
1191 VGA_WR08(ptr, reg, data);
1197 static Bool init_sub(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1199 CARD8 sub = *((CARD8 *) (&bios->data[offset + 1]));
1201 if (iexec->execute) {
1202 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: EXECUTING SUB-SCRIPT: %d\n", offset, sub);
1204 parse_init_table(pScrn, bios,
1205 *((CARD16 *) (&bios->data[bios->init_script_tbls_ptr + sub * 2])),
1208 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: END OF SUB-SCRIPT\n", offset);
1213 static Bool init_ram_condition(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1215 /* INIT_RAM_CONDITION opcode: 0x6D
1217 * offset (8 bit): opcode
1218 * offset + 1 (8 bit): and mask
1219 * offset + 2 (8 bit): cmpval
1221 * Test if (NV_PFB_BOOT & and mask) matches cmpval
1223 NVPtr pNv = NVPTR(pScrn);
1224 CARD8 and = *((CARD8 *) (&bios->data[offset + 1]));
1225 CARD8 cmpval = *((CARD8 *) (&bios->data[offset + 2]));
1228 if (iexec->execute) {
1229 data=(pNv->PFB[NV_PFB_BOOT/4])∧
1231 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1232 "0x%04X: CHECKING IF REGVAL: 0x%08X equals COND: 0x%08X\n",
1233 offset, data, cmpval);
1235 if (data == cmpval) {
1236 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1237 "0x%04X: CONDITION FULFILLED - CONTINUING TO EXECUTE\n",
1240 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CONDITION IS NOT FULFILLED.\n", offset);
1241 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1242 "0x%04X: ------ SKIPPING FOLLOWING COMMANDS ------\n", offset);
1243 iexec->execute = FALSE;
1249 static Bool init_nv_reg(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1251 /* INIT_NV_REG opcode: 0x6E ('n')
1253 * offset (8 bit): opcode
1254 * offset + 1 (32 bit): register
1255 * offset + 5 (32 bit): mask
1256 * offset + 9 (32 bit): data
1258 * Assign ((REGVAL("register") & "mask") | "data") to "register"
1261 uint32_t reg = *((uint32_t *)(&bios->data[offset + 1]));
1262 uint32_t mask = *((uint32_t *)(&bios->data[offset + 5]));
1263 uint32_t data = *((uint32_t *)(&bios->data[offset + 9]));
1266 if (!iexec->execute)
1269 if (DEBUGLEVEL >= 6)
1270 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1271 "0x%04X: Reg: 0x%08X, Mask: 0x%08X, Data: 0x%08X\n",
1272 offset, reg, mask, data);
1274 nv32_rd(pScrn, reg, &value);
1276 value = (value & mask) | data;
1278 nv32_wr(pScrn, reg, value);
1283 static Bool init_macro(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1285 /* INIT_MACRO opcode: 0x6F ('o')
1287 * offset (8 bit): opcode
1288 * offset + 1 (8 bit): macro number
1290 * Look up macro index "macro number" in the macro index table.
1291 * The macro index table entry has 1 byte for the index in the macro table,
1292 * and 1 byte for the number of times to repeat the macro.
1293 * The macro table entry has 4 bytes for the register address and
1294 * 4 bytes for the value to write to that register
1297 uint8_t macro_index_tbl_idx = *((uint8_t *)(&bios->data[offset + 1]));
1298 uint16_t tmp = bios->macro_index_tbl_ptr + (macro_index_tbl_idx * MACRO_INDEX_SIZE);
1299 uint8_t macro_tbl_idx = *((uint8_t *)(&bios->data[tmp]));
1300 uint8_t count = *((uint8_t *)(&bios->data[tmp + 1]));
1304 if (!iexec->execute)
1307 if (DEBUGLEVEL >= 6)
1308 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1309 "0x%04X: Macro: 0x%02X, MacroTableIndex: 0x%02X, Count: 0x%02X\n",
1310 offset, macro_index_tbl_idx, macro_tbl_idx, count);
1312 for (i = 0; i < count; i++) {
1313 reg = *((uint32_t *)
1314 (&bios->data[bios->macro_tbl_ptr + (macro_tbl_idx + i) * MACRO_SIZE]));
1315 data = *((uint32_t *)
1316 (&bios->data[bios->macro_tbl_ptr + (macro_tbl_idx + i) * MACRO_SIZE + 4]));
1318 nv32_wr(pScrn, reg, data);
1324 static Bool init_done(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1326 /* INIT_DONE opcode: 0x71 ('q')
1328 * offset (8 bit): opcode
1330 * End the current script
1333 /* mild retval abuse to stop parsing this table */
1337 static Bool init_resume(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1339 /* INIT_RESUME opcode: 0x72 ('r')
1341 * offset (8 bit): opcode
1343 * End the current execute / no-execute condition
1349 iexec->execute = TRUE;;
1350 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1351 "0x%04X: ---- EXECUTING FOLLOWING COMMANDS ----\n", offset);
1356 static Bool init_ram_condition2(ScrnInfoPtr pScrn, bios_t *bios, CARD16 offset, init_exec_t *iexec)
1358 /* INIT_RAM_CONDITION2 opcode: 0x73
1360 * offset (8 bit): opcode
1361 * offset + 1 (8 bit): and mask
1362 * offset + 2 (8 bit): cmpval
1364 * Test if (NV_EXTDEV_BOOT & and mask) matches cmpval
1366 NVPtr pNv = NVPTR(pScrn);
1367 CARD32 and = *((CARD32 *) (&bios->data[offset + 1]));
1368 CARD32 cmpval = *((CARD32 *) (&bios->data[offset + 5]));
1371 if (iexec->execute) {
1372 data=(nvReadEXTDEV(pNv, NV_PEXTDEV_BOOT))∧
1374 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1375 "0x%04X: CHECKING IF REGVAL: 0x%08X equals COND: 0x%08X\n",
1376 offset, data, cmpval);
1378 if (data == cmpval) {
1379 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1380 "0x%04X: CONDITION FULFILLED - CONTINUING TO EXECUTE\n",
1383 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: CONDITION IS NOT FULFILLED.\n", offset);
1384 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1385 "0x%04X: ------ SKIPPING FOLLOWING COMMANDS ------\n", offset);
1386 iexec->execute = FALSE;
1392 static Bool init_time(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1394 /* INIT_TIME opcode: 0x74 ('t')
1396 * offset (8 bit): opcode
1397 * offset + 1 (16 bit): time
1399 * Sleep for "time" microseconds.
1402 uint16_t time = *((uint16_t *)(&bios->data[offset + 1]));
1404 if (!iexec->execute)
1407 if (DEBUGLEVEL >= 6)
1408 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1409 "0x%04X: Sleeping for 0x%04X microseconds.\n", offset, time);
1416 static Bool init_condition(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1418 /* INIT_CONDITION opcode: 0x75 ('u')
1420 * offset (8 bit): opcode
1421 * offset + 1 (8 bit): condition number
1423 * Check condition "condition number" in the condition table.
1424 * The condition table entry has 4 bytes for the address of the
1425 * register to check, 4 bytes for a mask and 4 for a test value.
1426 * If condition not met skip subsequent opcodes until condition
1427 * is inverted (INIT_NOT), or we hit INIT_RESUME
1430 uint8_t cond = *((uint8_t *)(&bios->data[offset + 1]));
1431 uint16_t condptr = bios->condition_tbl_ptr + cond * CONDITION_SIZE;
1432 uint32_t reg = *((uint32_t *)
1433 (&bios->data[condptr]));
1434 uint32_t mask = *((uint32_t *)
1435 (&bios->data[condptr + 4]));
1436 uint32_t cmpval = *((uint32_t *)
1437 (&bios->data[condptr + 8]));
1440 if (!iexec->execute)
1443 if (DEBUGLEVEL >= 6)
1444 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1445 "0x%04X: Cond: 0x%02X, Reg: 0x%08X, Mask: 0x%08X, Cmpval: 0x%08X\n",
1446 offset, cond, reg, mask, cmpval);
1448 nv32_rd(pScrn, reg, &data);
1451 if (DEBUGLEVEL >= 6)
1452 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1453 "0x%04X: Checking if 0x%08X equals 0x%08X\n",
1454 offset, data, cmpval);
1456 if (data == cmpval) {
1457 if (DEBUGLEVEL >= 6)
1458 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1459 "0x%04X: CONDITION FULFILLED - CONTINUING TO EXECUTE\n", offset);
1461 if (DEBUGLEVEL >= 6)
1462 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1463 "0x%04X: CONDITION IS NOT FULFILLED.\n", offset);
1464 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1465 "0x%04X: ------ SKIPPING FOLLOWING COMMANDS ------\n", offset);
1466 iexec->execute = FALSE;
1472 static Bool init_index_io(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1474 /* INIT_INDEX_IO opcode: 0x78 ('x')
1476 * offset (8 bit): opcode
1477 * offset + 1 (16 bit): CRTC port
1478 * offset + 3 (8 bit): CRTC index
1479 * offset + 4 (8 bit): mask
1480 * offset + 5 (8 bit): data
1482 * Read value at index "CRTC index" on "CRTC port", AND with "mask", OR with "data", write-back
1485 uint16_t crtcport = *((uint16_t *)(&bios->data[offset + 1]));
1486 uint8_t crtcindex = *((uint8_t *)(&bios->data[offset + 3]));
1487 uint8_t mask = *((uint8_t *)(&bios->data[offset + 4]));
1488 uint8_t data = *((uint8_t *)(&bios->data[offset + 5]));
1491 if (!iexec->execute)
1494 if (DEBUGLEVEL >= 6)
1495 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1496 "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%08X, Data: 0x%08X\n",
1497 offset, crtcport, crtcindex, mask, data);
1499 /* FIXME how to choose head?? */
1500 nv_port_rd(pScrn, crtcport, crtcindex, &value, 0);
1501 value = (value & mask) | data;
1502 nv_port_wr(pScrn, crtcport, crtcindex, value, 0);
1507 static Bool init_zm_reg(ScrnInfoPtr pScrn, bios_t *bios, uint16_t offset, init_exec_t *iexec)
1509 /* INIT_ZM_REG opcode: 0x7A ('z')
1511 * offset (8 bit): opcode
1512 * offset + 1 (32 bit): register
1513 * offset + 5 (32 bit): value
1515 * Assign "value" to "register"
1518 uint32_t reg = *((uint32_t *)(&bios->data[offset + 1]));
1519 uint32_t value = *((uint32_t *)(&bios->data[offset + 5]));
1521 if (!iexec->execute)
1524 nv32_wr(pScrn, reg, value);
1529 static init_tbl_entry_t itbl_entry[] = {
1530 /* command name , id , length , offset , mult , command handler */
1531 { "INIT_PROG" , 0x31, 15 , 10 , 4 , init_prog },
1532 { "INIT_IO_RESTRICT_PROG" , 0x32, 11 , 6 , 4 , init_io_restrict_prog },
1533 { "INIT_REPEAT" , 0x33, 2 , 0 , 0 , init_repeat },
1534 { "INIT_IO_RESTRICT_PLL" , 0x34, 12 , 7 , 2 , init_io_restrict_pll },
1535 { "INIT_END_REPEAT" , 0x36, 1 , 0 , 0 , init_end_repeat },
1536 { "INIT_COPY" , 0x37, 11 , 0 , 0 , init_copy },
1537 { "INIT_NOT" , 0x38, 1 , 0 , 0 , init_not },
1538 { "INIT_IO_FLAG_CONDITION" , 0x39, 2 , 0 , 0 , init_io_flag_condition },
1539 { "INIT_INDEX_ADDRESS_LATCHED" , 0x49, 18 , 17 , 2 , init_idx_addr_latched },
1540 /* { "INIT_IO_RESTRICT_PLL" , 0x4A, 43 , 0 , 0 , init_io_restrict_pll }, */
1541 /* { "INIT_PLL" , 0x4B, 9 , 0 , 0 , init_pll }, */
1542 /* { "INIT_I2C_BYTE" , 0x4C, x , x , x , init_i2c_byte }, */
1543 /* { "INIT_ZM_I2C_BYTE" , 0x4D, x , x , x , init_zm_i2c_byte }, */
1544 /* { "INIT_ZM_I2C" , 0x4E, x , x , x , init_zm_i2c }, */
1545 { "INIT_CR_INDEX_ADDRESS_LATCHED" , 0x51, 5 , 4 , 1 , init_cr_idx_adr_latch },
1546 { "INIT_CR" , 0x52, 4 , 0 , 0 , init_cr },
1547 { "INIT_ZM_CR" , 0x53, 3 , 0 , 0 , init_zm_cr },
1548 { "INIT_ZM_CR_GROUP" , 0x54, 2 , 1 , 2 , init_zm_cr_group },
1549 { "INIT_CONDITION_TIME" , 0x56, 3 , 0 , 0 , init_condition_time },
1550 { "INIT_ZM_REG_SEQUENCE" , 0x58, 6 , 5 , 4 , init_zm_reg_sequence },
1551 { "INIT_INDIRECT_REG" , 0x5A, 7 , 0 , 0 , init_indirect_reg },
1552 { "INIT_SUB_DIRECT" , 0x5B, 3 , 0 , 0 , init_sub_direct },
1553 { "INIT_COPY_NV_REG" , 0x5F, 22 , 0 , 0 , init_copy_nv_reg },
1554 { "INIT_ZM_INDEX_IO" , 0x62, 5 , 0 , 0 , init_zm_index_io },
1555 { "INIT_COMPUTE_MEM" , 0x63, 1 , 0 , 0 , init_compute_mem },
1556 { "INIT_RESET" , 0x65, 13 , 0 , 0 , init_reset },
1557 /* { "INIT_NEXT" , 0x66, x , x , x , init_next }, */
1558 /* { "INIT_NEXT" , 0x67, x , x , x , init_next }, */
1559 /* { "INIT_NEXT" , 0x68, x , x , x , init_next }, */
1560 { "INIT_INDEX_IO8" , 0x69, 5 , 0 , 0 , init_index_io8 },
1561 { "INIT_SUB" , 0x6B, 2 , 0 , 0 , init_sub },
1562 { "INIT_RAM_CONDITION" , 0x6D, 3 , 0 , 0 , init_ram_condition },
1563 { "INIT_NV_REG" , 0x6E, 13 , 0 , 0 , init_nv_reg },
1564 { "INIT_MACRO" , 0x6F, 2 , 0 , 0 , init_macro },
1565 { "INIT_DONE" , 0x71, 1 , 0 , 0 , init_done },
1566 { "INIT_RESUME" , 0x72, 1 , 0 , 0 , init_resume },
1567 { "INIT_RAM_CONDITION2" , 0x73, 9 , 0 , 0 , init_ram_condition2 },
1568 { "INIT_TIME" , 0x74, 3 , 0 , 0 , init_time },
1569 { "INIT_CONDITION" , 0x75, 2 , 0 , 0 , init_condition },
1570 /* { "INIT_IO_CONDITION" , 0x76, x , x , x , init_io_condition }, */
1571 { "INIT_INDEX_IO" , 0x78, 6 , 0 , 0 , init_index_io },
1572 { "INIT_PLL" , 0x79, 7 , 0 , 0 , init_pll },
1573 { "INIT_ZM_REG" , 0x7A, 9 , 0 , 0 , init_zm_reg },
1574 /* { "INIT_RAM_RESTRICT_ZM_REG_GROUP" , 0x8F, x , x , x , init_ram_restrict_zm_reg_group }, */
1575 /* { "INIT_COPY_ZM_REG" , 0x90, x , x , x , init_copy_zm_reg }, */
1576 /* { "INIT_ZM_REG_GROUP_ADDRESS_LATCHED" , 0x91, x , x , x , init_zm_reg_group_addr_latched }, */
1577 /* { "INIT_RESERVED" , 0x92, x , x , x , init_reserved }, */
1578 { 0 , 0 , 0 , 0 , 0 , 0 }
1581 static unsigned int get_init_table_entry_length(bios_t *bios, unsigned int offset, int i)
1583 /* Calculates the length of a given init table entry. */
1584 return itbl_entry[i].length + bios->data[offset + itbl_entry[i].length_offset]*itbl_entry[i].length_multiplier;
1587 static void parse_init_table(ScrnInfoPtr pScrn, bios_t *bios, unsigned int offset, init_exec_t *iexec)
1589 /* Parses all commands in a init table. */
1591 /* We start out executing all commands found in the
1592 * init table. Some op codes may change the status
1593 * of this variable to SKIP, which will cause
1594 * the following op codes to perform no operation until
1595 * the value is changed back to EXECUTE.
1601 /* Loop until INIT_DONE causes us to break out of the loop
1602 * (or until offset > bios length just in case... )
1603 * (and no more than 10000 iterations just in case... ) */
1604 while ((offset < bios->length) && (count++ < 10000)) {
1605 id = bios->data[offset];
1607 /* Find matching id in itbl_entry */
1608 for (i = 0; itbl_entry[i].name && (itbl_entry[i].id != id); i++)
1611 if (itbl_entry[i].name) {
1612 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: [ (0x%02X) - %s ]\n",
1613 offset, itbl_entry[i].id, itbl_entry[i].name);
1615 /* execute eventual command handler */
1616 if (itbl_entry[i].handler)
1617 if (!(*itbl_entry[i].handler)(pScrn, bios, offset, iexec))
1620 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1621 "0x%04X: Init table command not found: 0x%02X\n", offset, id);
1625 /* Add the offset of the current command including all data
1626 * of that command. The offset will then be pointing on the
1629 offset += get_init_table_entry_length(bios, offset, i);
1633 void parse_init_tables(ScrnInfoPtr pScrn, bios_t *bios)
1635 /* Loops and calls parse_init_table() for each present table. */
1639 init_exec_t iexec = {TRUE, FALSE};
1641 while ((table = *((uint16_t *)(&bios->data[bios->init_script_tbls_ptr + i])))) {
1643 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "0x%04X: Parsing init table %d\n",
1646 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1647 "0x%04X: ------ EXECUTING FOLLOWING COMMANDS ------\n", table);
1649 parse_init_table(pScrn, bios, table, &iexec);
1654 static void parse_fp_tables(ScrnInfoPtr pScrn, bios_t *bios)
1656 NVPtr pNv = NVPTR(pScrn);
1657 unsigned int fpstrapping;
1658 uint8_t *fptable, *fpxlatetable;
1659 /* uint8_t *lvdsmanufacturertable, *fpxlatemanufacturertable;*/
1660 unsigned int fpindex;/* lvdsmanufacturerindex;*/
1661 uint8_t fptable_ver, headerlen = 0, recordlen = 44;
1663 DisplayModePtr mode;
1665 fpstrapping = (nvReadEXTDEV(pNv, NV_PEXTDEV_BOOT) >> 16) & 0xf;
1667 if (bios->fptablepointer == 0x0) {
1668 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1669 "Pointer to flat panel table invalid\n");
1673 fptable = &bios->data[bios->fptablepointer];
1675 fptable_ver = fptable[0];
1677 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1678 "Found flat panel mode table revision %d.%d\n",
1679 fptable_ver >> 4, fptable_ver & 0xf);
1681 switch (fptable_ver) {
1682 /* PINS version 0x5.0x11 BIOSen have version 1 like tables, but no version field,
1683 * and miss one of the spread spectrum/PWM bytes.
1684 * This could affect early GF2Go parts (not seen any appropriate ROMs though).
1685 * Here we assume that a version of 0x00 matches this case (combining with a
1686 * PINS version check would be better), as the common case for the panel type
1687 * field is 0x0005, and that is in fact what we are reading the first byte of. */
1688 case 0x00: /* some NV11, 15, 16 */
1689 /* note that in this version the lvdsmanufacturertable is not defined */
1693 case 0x10: /* some NV15/16, and NV11+ */
1696 if (bios->fpxlatetableptr == 0x0) {
1697 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1698 "Pointer to flat panel translation table invalid\n");
1701 fpxlatetable = &bios->data[bios->fpxlatetableptr];
1703 lvdsmanufacturertable = &bios->data[bios->lvdsmanufacturerpointer];
1704 fpxlatemanufacturertable = &bios->data[bios->fpxlatemanufacturertableptr];*/
1706 fpindex = fpxlatetable[fpstrapping];
1708 lvdsmanufacturerindex = fpxlatemanufacturertable[fpstrapping]; */
1710 if (fpindex > 0xf) {
1711 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1712 "Bad flat panel table index\n");
1716 case 0x20: /* NV40+ */
1717 headerlen = fptable[1];
1718 recordlen = fptable[2]; // check this, or hardcode as 0x20
1719 /* may be the wrong test, if there's a translation table
1720 if (fpstrapping > fptable[3]) {
1721 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1722 "Flat panel strapping number too high\n");
1726 /* I don't know where the index for the table comes from in v2.0, so bail
1729 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1730 "FP Table revision not currently supported\n");
1734 if (!(mode = xcalloc(1, sizeof(DisplayModeRec))))
1737 int modeofs = headerlen + recordlen * fpindex + ofs;
1738 mode->Clock = *(uint16_t *)&fptable[modeofs] * 10;
1739 mode->HDisplay = *(uint16_t *)&fptable[modeofs + 2];
1740 mode->HSyncStart = *(uint16_t *)&fptable[modeofs + 10] + 1;
1741 mode->HSyncEnd = *(uint16_t *)&fptable[modeofs + 12] + 1;
1742 mode->HTotal = *(uint16_t *)&fptable[modeofs + 14] + 1;
1743 mode->VDisplay = *(uint16_t *)&fptable[modeofs + 16];
1744 mode->VSyncStart = *(uint16_t *)&fptable[modeofs + 24] + 1;
1745 mode->VSyncEnd = *(uint16_t *)&fptable[modeofs + 26] + 1;
1746 mode->VTotal = *(uint16_t *)&fptable[modeofs + 28] + 1;
1747 mode->Flags |= (fptable[modeofs + 30] & 0x10) ? V_PHSYNC : V_NHSYNC;
1748 mode->Flags |= (fptable[modeofs + 30] & 0x1) ? V_PVSYNC : V_NVSYNC;
1751 * bytes 1-2 are "panel type", including bits on whether Colour/mono, single/dual link, and type (TFT etc.)
1752 * bytes 3-6 are bits per colour in RGBX
1754 * 13-14 is HValid Start
1755 * 15-16 is HValid End
1756 * bytes 38-39 relate to spread spectrum settings
1757 * bytes 40-43 are something to do with PWM */
1759 mode->prev = mode->next = NULL;
1760 mode->status = MODE_OK;
1761 mode->type = M_T_DRIVER | M_T_PREFERRED;
1762 xf86SetModeDefaultName(mode);
1764 // if (pNv->debug_modes) { this should exist
1765 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1766 "Found flat panel mode in BIOS tables:\n");
1767 xf86PrintModeline(pScrn->scrnIndex, mode);
1770 pNv->fp_native_mode = mode;
1773 static int parse_bit_display_tbl_entry(ScrnInfoPtr pScrn, bios_t *bios, bit_entry_t *bitentry)
1776 /* Parses the flat panel table segment that the bit entry points to.
1777 * Starting at bitentry->offset:
1779 * offset + 0 (16 bits): FIXME table pointer
1780 * offset + 2 (16 bits): mode table pointer
1783 /* If it's not a laptop, you probably don't care about fptables */
1784 /* FIXME: detect mobile BIOS? */
1786 NVPtr pNv = NVPTR(pScrn);
1791 if (bitentry->length != 4) {
1792 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1793 "Do not understand BIT display table entry.\n");
1797 table = *((uint16_t *)(&bios->data[bitentry->offset]));
1798 bios->fptablepointer = *((uint16_t *)(&bios->data[bitentry->offset + 2]));
1800 parse_fp_tables(pScrn, bios);
1805 static unsigned int parse_bit_init_tbl_entry(ScrnInfoPtr pScrn, bios_t *bios, bit_entry_t *bitentry)
1807 /* Parses the init table segment that the bit entry points to.
1808 * Starting at bitentry->offset:
1810 * offset + 0 (16 bits): init script tables pointer
1811 * offset + 2 (16 bits): macro index table pointer
1812 * offset + 4 (16 bits): macro table pointer
1813 * offset + 6 (16 bits): condition table pointer
1814 * offset + 8 (16 bits): io condition table pointer
1815 * offset + 10 (16 bits): io flag condition table pointer
1816 * offset + 12 (16 bits): init function table pointer
1819 * * Are 'I' bit entries always of length 0xE?
1823 if (bitentry->length < 12) {
1824 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1825 "Unable to recognize BIT init table entry.\n");
1829 bios->init_script_tbls_ptr = *((uint16_t *)(&bios->data[bitentry->offset]));
1830 bios->macro_index_tbl_ptr = *((uint16_t *)(&bios->data[bitentry->offset + 2]));
1831 bios->macro_tbl_ptr = *((uint16_t *)(&bios->data[bitentry->offset + 4]));
1832 bios->condition_tbl_ptr = *((uint16_t *)(&bios->data[bitentry->offset + 6]));
1833 bios->io_condition_tbl_ptr = *((uint16_t *)(&bios->data[bitentry->offset + 8]));
1834 bios->io_flag_condition_tbl_ptr = *((uint16_t *)(&bios->data[bitentry->offset + 10]));
1835 bios->init_function_tbl_ptr = *((uint16_t *)(&bios->data[bitentry->offset + 12]));
1837 parse_init_tables(pScrn, bios);
1842 static unsigned int parse_bmp_table_pointers(ScrnInfoPtr pScrn, bios_t *bios, bit_entry_t *bitentry)
1844 /* Parse the pointers for useful tables in the BMP structure, starting at
1845 * offset 75 from the ..NV. signature.
1847 * First 7 pointers as for parse_bit_init_tbl_entry
1849 * offset + 30: flat panel timings table pointer
1850 * offset + 32: flat panel strapping translation table pointer
1851 * offset + 42: LVDS manufacturer panel config table pointer
1852 * offset + 44: LVDS manufacturer strapping translation table pointer
1855 NVPtr pNv = NVPTR(pScrn);
1857 if (!parse_bit_init_tbl_entry(pScrn, bios, bitentry))
1860 /* If it's not a laptop, you probably don't care about fptables */
1861 /* FIXME: detect mobile BIOS? */
1865 if (bitentry->length > 33) {
1866 bios->fptablepointer = *((uint16_t *)(&bios->data[bitentry->offset + 30]));
1867 bios->fpxlatetableptr = *((uint16_t *)(&bios->data[bitentry->offset + 32]));
1869 if (bitentry->length > 45) {
1870 bios->lvdsmanufacturerpointer = *((uint16_t *)(&bios->data[bitentry->offset + 42]));
1871 bios->fpxlatemanufacturertableptr = *((uint16_t *)(&bios->data[bitentry->offset + 44]));
1874 parse_fp_tables(pScrn, bios);
1879 static void parse_bit_structure(ScrnInfoPtr pScrn, bios_t *bios, unsigned int offset)
1881 bit_entry_t *bitentry;
1885 bitentry = (bit_entry_t *) &bios->data[offset];
1887 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1888 "0x%04X: Found BIT command with id 0x%02X\n",
1889 offset, bitentry->id[0]);
1891 switch (bitentry->id[0]) {
1893 /* id[0] = 0 and id[1] = 0 ==> end of BIT struture */
1894 if (bitentry->id[1] == 0)
1898 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1899 "0x%04X: Found flat panel display table entry in BIT structure.\n", offset);
1900 parse_bit_display_tbl_entry(pScrn, bios, bitentry);
1903 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1904 "0x%04X: Found init table entry in BIT structure.\n", offset);
1906 parse_bit_init_tbl_entry(pScrn, bios, bitentry);
1909 /* TODO: What kind of information does the other BIT entrys point to?
1910 * 'P' entry is probably performance tables, but there are
1911 * quite a few others...
1915 offset += sizeof(bit_entry_t);
1919 static void parse_pins_structure(ScrnInfoPtr pScrn, bios_t *bios, unsigned int offset)
1921 int pins_version_major=bios->data[offset+5];
1922 int pins_version_minor=bios->data[offset+6];
1923 int init1 = bios->data[offset + 18] + (bios->data[offset + 19] * 256);
1924 int init2 = bios->data[offset + 20] + (bios->data[offset + 21] * 256);
1925 int init_size = bios->data[offset + 22] + (bios->data[offset + 23] * 256) + 1;
1928 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PINS version %d.%d\n",
1929 pins_version_major, pins_version_minor);
1932 if (nv_cksum(bios->data, offset, 8)) {
1933 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "bad PINS checksum\n");
1937 switch(pins_version_major) {
1939 ram_tab = init1-0x0010;
1944 ram_tab = bios->data[offset + 24] + (bios->data[offset + 25] * 256);
1950 if ((pins_version_major==5)&&(pins_version_minor>=6)) {
1951 /* VCO range info */
1954 if ((pins_version_major==5)&&(pins_version_minor>=16)) {
1955 bit_entry_t bitentry;
1957 if (pins_version_minor == 0x10)
1958 bitentry.length = 12; /* I've not seen this version, so be "long enough" */
1959 else if (pins_version_minor < 0x14)
1960 bitentry.length = 34;
1962 bitentry.length = 48; /* versions after 0x14 are longer,
1963 but extra contents unneeded ATM */
1965 bitentry.offset = offset + 75;
1966 parse_bmp_table_pointers(pScrn, bios, &bitentry);
1968 /* TODO type1 script */
1972 static unsigned int findstr(bios_t* bios, unsigned char *str, int len)
1976 for (i = 2; i <= (bios->length - len); i++)
1977 if (strncmp((char *)&bios->data[i], (char *)str, len) == 0)
1983 static Bool parse_dcb_entry(uint8_t dcb_version, uint32_t conn, uint32_t conf, struct dcb_entry *entry)
1985 if (dcb_version >= 0x20) {
1986 entry->type = conn & 0xf;
1987 entry->i2c_index = (conn >> 4) & 0xf;
1988 entry->head = (conn >> 8) & 0xf;
1989 entry->bus = (conn >> 16) & 0xf;
1990 entry->or = (conn >> 24) & 0xf;
1991 } else if (dcb_version >= 0x14 ) {
1992 // 1.4 needs more loving
1994 entry->i2c_index = 0;
2000 // 1.2 needs more loving
2002 entry->i2c_index = 0;
2013 read_dcb_i2c_table(ScrnInfoPtr pScrn, bios_t *bios, uint8_t dcb_version, uint16_t i2ctabptr)
2015 NVPtr pNv = NVPTR(pScrn);
2017 uint8_t headerlen = 0;
2019 int recordoffset = 0, rdofs = 1, wrofs = 0;
2022 i2c_entries = MAX_NUM_DCB_ENTRIES;
2023 memset(pNv->dcb_table.i2c_read, 0, sizeof(pNv->dcb_table.i2c_read));
2024 memset(pNv->dcb_table.i2c_write, 0, sizeof(pNv->dcb_table.i2c_write));
2026 i2ctable = &bios->data[i2ctabptr];
2028 if (dcb_version >= 0x30) {
2029 if (i2ctable[0] != dcb_version) { /* necessary? */
2030 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2031 "DCB I2C table version mismatch (%02X vs %02X)\n",
2032 i2ctable[0], dcb_version);
2035 headerlen = i2ctable[1];
2036 i2c_entries = i2ctable[2];
2037 if (i2ctable[0] >= 0x40) {
2038 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2039 "G80 DCB I2C table detected, arrgh\n"); /* they're plain weird */
2043 /* it's your own fault if you call this function on a DCB 1.1 BIOS */
2044 if (dcb_version < 0x14) {
2050 for (i = 0; i < i2c_entries; i++) {
2051 if (i2ctable[headerlen + 4 * i + 3] != 0xff) {
2052 pNv->dcb_table.i2c_read[i] = i2ctable[headerlen + recordoffset + rdofs + 4 * i];
2053 pNv->dcb_table.i2c_write[i] = i2ctable[headerlen + recordoffset + wrofs + 4 * i];
2058 #define G5_NV43_FIXED_LOC 0xe31b
2060 static unsigned int parse_dcb_table(ScrnInfoPtr pScrn, bios_t *bios)
2062 NVPtr pNv = NVPTR(pScrn);
2063 uint16_t dcbptr, i2ctabptr = 0;
2064 Bool is_g5_nv43 = FALSE;
2066 uint8_t dcb_version, headerlen = 0x4, entries = MAX_NUM_DCB_ENTRIES;
2067 Bool configblock = TRUE;
2068 int recordlength = 8, confofs = 4;
2071 pNv->dcb_table.entries = 0;
2073 /* get the offset from 0x36 */
2074 dcbptr = *(uint16_t *)&bios->data[0x36];
2076 if (dcbptr == 0x0) {
2077 if ((pNv->Chipset & 0x0ff0) == CHIPSET_NV43) {
2078 dcbptr = G5_NV43_FIXED_LOC;
2081 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2082 "No Display Configuration Block pointer found\n");
2087 dcbtable = &bios->data[dcbptr];
2089 /* get DCB version */
2090 dcb_version = dcbtable[0];
2091 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2092 "Display Configuration Block version %d.%d found\n",
2093 dcb_version >> 4, dcb_version & 0xf);
2095 if (dcb_version >= 0x20) { /* NV17+ */
2098 if (dcb_version >= 0x30) { /* NV40+ */
2099 headerlen = dcbtable[1];
2100 entries = dcbtable[2];
2101 i2ctabptr = *(uint16_t *)&dcbtable[4];
2102 sig = *(uint32_t *)&dcbtable[6];
2104 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2105 "DCB header length %02X, with %02X possible entries\n",
2106 headerlen, entries);
2108 /* dcb_block_count = *(dcbtable[1]); */
2109 i2ctabptr = *(uint16_t *)&dcbtable[2];
2110 sig = *(uint32_t *)&dcbtable[4];
2114 if (sig != 0x4edcbdcb) {
2115 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2116 "Bad Display Configuration Block signature (%08X)\n", sig);
2119 } else if (dcb_version >= 0x14) { /* some NV15/16, and NV11+ */
2123 strncpy(sig, (char *)&dcbtable[-7], 7);
2124 /* dcb_block_count = *(dcbtable[1]); */
2125 i2ctabptr = *(uint16_t *)&dcbtable[2];
2129 if (strcmp(sig, "DEV_REC")) {
2130 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2131 "Bad Display Configuration Block signature (%s)\n", sig);
2134 } else if (dcb_version >= 0x12) { /* some NV6/10, and NV15+ */
2135 /* dcb_block_count = *(dcbtable[1]); */
2136 i2ctabptr = *(uint16_t *)&dcbtable[2];
2137 configblock = FALSE;
2138 } else { /* NV5+, maybe NV4 */
2139 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2140 "Structure of Display Configuration Blocks prior to version 1.2 unknown\n");
2144 if (entries >= MAX_NUM_DCB_ENTRIES)
2145 entries = MAX_NUM_DCB_ENTRIES;
2147 for (i = 0; i < entries; i++) {
2148 uint32_t connection, config = 0;
2151 connection = __bswap_32(*(uint32_t *)&dcbtable[headerlen + recordlength * i]);
2153 config = __bswap_32(*(uint32_t *)&dcbtable[headerlen + confofs + recordlength * i]);
2155 connection = *(uint32_t *)&dcbtable[headerlen + recordlength * i];
2157 config = *(uint32_t *)&dcbtable[headerlen + confofs + recordlength * i];
2160 /* I think this is a good descriminator, but I don't understand
2161 * pre v2.0 DCBs so well, so maybe those need testing against
2163 /* Should we allow discontinuous DCBs? Certainly DCB I2C tables
2164 * can be discontinuous */
2165 if ((connection & 0x0f000000) == 0x0f000000) /* end of records */
2168 ErrorF("Raw DCB entry %d: %08x\n", i, connection);
2169 if (!parse_dcb_entry(dcb_version, connection, config, &pNv->dcb_table.entry[i]))
2172 pNv->dcb_table.entries = i;
2174 /* the G5 6600 uses a relative address */
2176 i2ctabptr += G5_NV43_FIXED_LOC;
2178 read_dcb_i2c_table(pScrn, bios, dcb_version, i2ctabptr);
2180 return pNv->dcb_table.entries;
2183 unsigned int NVParseBios(ScrnInfoPtr pScrn)
2185 unsigned int bit_offset;
2188 bios.fptablepointer = 0;
2189 uint8_t nv_signature[]={0xff,0x7f,'N','V',0x0};
2190 uint8_t bit_signature[]={'B','I','T'};
2194 pNv->dcb_table.entries = 0;
2195 pNv->fp_native_mode = NULL;
2197 pNv->VBIOS = xalloc(64 * 1024);
2198 if (!NVShadowVBIOS(pScrn, pNv->VBIOS)) {
2199 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2200 "No valid BIOS image found.\n");
2204 bios.data = (uint8_t *)pNv->VBIOS;
2205 bios.length = bios.data[2] * 512;
2206 if (bios.length > NV_PROM_SIZE)
2207 bios.length = NV_PROM_SIZE;
2209 /* check for known signatures */
2210 if ((bit_offset = findstr(&bios, bit_signature, sizeof(bit_signature)))) {
2211 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIT signature found.\n");
2212 parse_bit_structure(pScrn, &bios, bit_offset + 4);
2213 } else if ((bit_offset = findstr(&bios, nv_signature, sizeof(nv_signature)))) {
2214 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "NV signature found.\n");
2215 parse_pins_structure(pScrn, &bios, bit_offset);
2217 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2218 "No known script signature found.\n");
2220 /* parse Display Configuration Block (DCB) table */
2221 if (parse_dcb_table(pScrn, &bios))
2222 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2223 "Found %d entries in DCB.\n", pNv->dcb_table.entries);