1 /* 2 * i2c interface. 3 * Bus should be run at max. 100kHz: see original Philips I2C specification 4 * 5 * Rudolf Cornelissen 12/2002-5/2009 6 */ 7 8 #define MODULE_BIT 0x00004000 9 10 #include "nv_std.h" 11 12 static void i2c_DumpSpecsEDID(edid_specs* specs); 13 14 char i2c_flag_error (char ErrNo) 15 //error code list: 16 //0 - OK status 17 //1 - SCL locked low by device (bus is still busy) 18 //2 - SDA locked low by device (bus is still busy) 19 //3 - No Acknowledge from device (no handshake) 20 //4 - SDA not released for master to generate STOP bit 21 { 22 static char I2CError = 0; 23 24 if (!I2CError) I2CError = ErrNo; 25 if (ErrNo == -1) I2CError = 0; 26 return I2CError; 27 } 28 29 static void i2c_select_bus_set(bool set) 30 { 31 /* I/O pins set selection is only valid on dualhead cards */ 32 if (!si->ps.secondary_head) return; 33 34 /* select GPU I/O pins set to connect to I2C 'registers' */ 35 if (set) 36 { 37 NV_REG32(NV32_FUNCSEL) &= ~0x00000010; 38 NV_REG32(NV32_2FUNCSEL) |= 0x00000010; 39 } 40 else 41 { 42 NV_REG32(NV32_2FUNCSEL) &= ~0x00000010; 43 NV_REG32(NV32_FUNCSEL) |= 0x00000010; 44 } 45 } 46 47 static void OutSCL(uint8 BusNR, bool Bit) 48 { 49 uint8 data; 50 51 if (BusNR & 0x01) 52 { 53 data = (CRTCR(WR_I2CBUS_1) & 0xf0) | 0x01; 54 if (Bit) 55 CRTCW(WR_I2CBUS_1, (data | 0x20)); 56 else 57 CRTCW(WR_I2CBUS_1, (data & ~0x20)); 58 } 59 else 60 { 61 data = (CRTCR(WR_I2CBUS_0) & 0xf0) | 0x01; 62 if (Bit) 63 CRTCW(WR_I2CBUS_0, (data | 0x20)); 64 else 65 CRTCW(WR_I2CBUS_0, (data & ~0x20)); 66 } 67 } 68 69 static void OutSDA(uint8 BusNR, bool Bit) 70 { 71 uint8 data; 72 73 if (BusNR & 0x01) 74 { 75 data = (CRTCR(WR_I2CBUS_1) & 0xf0) | 0x01; 76 if (Bit) 77 CRTCW(WR_I2CBUS_1, (data | 0x10)); 78 else 79 CRTCW(WR_I2CBUS_1, (data & ~0x10)); 80 } 81 else 82 { 83 data = (CRTCR(WR_I2CBUS_0) & 0xf0) | 0x01; 84 if (Bit) 85 CRTCW(WR_I2CBUS_0, (data | 0x10)); 86 else 87 CRTCW(WR_I2CBUS_0, (data & ~0x10)); 88 } 89 } 90 91 static bool InSCL(uint8 BusNR) 92 { 93 if (BusNR & 0x01) 94 { 95 if ((CRTCR(RD_I2CBUS_1) & 0x04)) return true; 96 } 97 else 98 { 99 if ((CRTCR(RD_I2CBUS_0) & 0x04)) return true; 100 } 101 102 return false; 103 } 104 105 static bool InSDA(uint8 BusNR) 106 { 107 if (BusNR & 0x01) 108 { 109 if ((CRTCR(RD_I2CBUS_1) & 0x08)) return true; 110 } 111 else 112 { 113 if ((CRTCR(RD_I2CBUS_0) & 0x08)) return true; 114 } 115 116 return false; 117 } 118 119 static void TXBit (uint8 BusNR, bool Bit) 120 { 121 /* send out databit */ 122 if (Bit) 123 { 124 OutSDA(BusNR, true); 125 snooze(3); 126 if (!InSDA(BusNR)) i2c_flag_error (2); 127 } 128 else 129 { 130 OutSDA(BusNR, false); 131 } 132 /* generate clock pulse */ 133 snooze(6); 134 OutSCL(BusNR, true); 135 snooze(3); 136 if (!InSCL(BusNR)) i2c_flag_error (1); 137 snooze(6); 138 OutSCL(BusNR, false); 139 snooze(6); 140 } 141 142 static uint8 RXBit (uint8 BusNR) 143 { 144 uint8 Bit = 0; 145 146 /* set SDA so input is possible */ 147 OutSDA(BusNR, true); 148 /* generate clock pulse */ 149 snooze(6); 150 OutSCL(BusNR, true); 151 snooze(3); 152 if (!InSCL(BusNR)) i2c_flag_error (1); 153 snooze(3); 154 /* read databit */ 155 if (InSDA(BusNR)) Bit = 1; 156 /* finish clockpulse */ 157 OutSCL(BusNR, false); 158 snooze(6); 159 160 return Bit; 161 } 162 163 void i2c_bstart (uint8 BusNR) 164 { 165 /* select GPU I/O pins set */ 166 i2c_select_bus_set(BusNR & 0x02); 167 168 /* enable access to primary head */ 169 set_crtc_owner(0); 170 171 /* make sure SDA is high */ 172 OutSDA(BusNR, true); 173 snooze(3); 174 OutSCL(BusNR, true); 175 snooze(3); 176 if (!InSCL(BusNR)) i2c_flag_error (1); 177 snooze(6); 178 /* clear SDA while SCL set (bus-start condition) */ 179 OutSDA(BusNR, false); 180 snooze(6); 181 OutSCL(BusNR, false); 182 snooze(6); 183 184 LOG(4,("I2C: START condition generated on bus %d; status is %d\n", 185 BusNR, i2c_flag_error (0))); 186 } 187 188 void i2c_bstop (uint8 BusNR) 189 { 190 /* select GPU I/O pins set */ 191 i2c_select_bus_set(BusNR & 0x02); 192 193 /* enable access to primary head */ 194 set_crtc_owner(0); 195 196 /* make sure SDA is low */ 197 OutSDA(BusNR, false); 198 snooze(3); 199 OutSCL(BusNR, true); 200 snooze(3); 201 if (!InSCL(BusNR)) i2c_flag_error (1); 202 snooze(6); 203 /* set SDA while SCL set (bus-stop condition) */ 204 OutSDA(BusNR, true); 205 snooze(3); 206 if (!InSDA(BusNR)) i2c_flag_error (4); 207 snooze(3); 208 209 LOG(4,("I2C: STOP condition generated on bus %d; status is %d\n", 210 BusNR, i2c_flag_error (0))); 211 } 212 213 uint8 i2c_readbyte(uint8 BusNR, bool Ack) 214 { 215 uint8 cnt, bit, byte = 0; 216 217 /* select GPU I/O pins set */ 218 i2c_select_bus_set(BusNR & 0x02); 219 220 /* enable access to primary head */ 221 set_crtc_owner(0); 222 223 /* read data */ 224 for (cnt = 8; cnt > 0; cnt--) 225 { 226 byte <<= 1; 227 bit = RXBit (BusNR); 228 byte += bit; 229 } 230 /* send acknowledge */ 231 TXBit (BusNR, Ack); 232 233 LOG(4,("I2C: read byte ($%02x) from bus #%d; status is %d\n", 234 byte, BusNR, i2c_flag_error(0))); 235 236 return byte; 237 } 238 239 bool i2c_writebyte (uint8 BusNR, uint8 byte) 240 { 241 uint8 cnt; 242 bool bit; 243 uint8 tmp = byte; 244 245 /* select GPU I/O pins set */ 246 i2c_select_bus_set(BusNR & 0x02); 247 248 /* enable access to primary head */ 249 set_crtc_owner(0); 250 251 /* write data */ 252 for (cnt = 8; cnt > 0; cnt--) 253 { 254 bit = (tmp & 0x80); 255 TXBit (BusNR, bit); 256 tmp <<= 1; 257 } 258 /* read acknowledge */ 259 bit = RXBit (BusNR); 260 if (bit) i2c_flag_error (3); 261 262 LOG(4,("I2C: written byte ($%02x) to bus #%d; status is %d\n", 263 byte, BusNR, i2c_flag_error(0))); 264 265 return bit; 266 } 267 268 void i2c_readbuffer (uint8 BusNR, uint8* buf, uint8 size) 269 { 270 uint8 cnt; 271 272 for (cnt = 0; cnt < size; cnt++) 273 { 274 buf[cnt] = i2c_readbyte(BusNR, buf[cnt]); 275 } 276 } 277 278 void i2c_writebuffer (uint8 BusNR, uint8* buf, uint8 size) 279 { 280 uint8 cnt; 281 282 for (cnt = 0; cnt < size; cnt++) 283 { 284 i2c_writebyte(BusNR, buf[cnt]); 285 } 286 } 287 288 status_t i2c_init(void) 289 { 290 uint8 bus, buses; 291 bool *i2c_bus = &(si->ps.i2c_bus0); 292 status_t result = B_ERROR; 293 294 LOG(4,("I2C: searching for wired I2C buses...\n")); 295 296 /* enable access to primary head */ 297 set_crtc_owner(0); 298 299 /* preset no board wired buses */ 300 si->ps.i2c_bus0 = false; 301 si->ps.i2c_bus1 = false; 302 si->ps.i2c_bus2 = false; 303 si->ps.i2c_bus3 = false; 304 305 /* set number of buses to test for */ 306 buses = 2; 307 if (si->ps.secondary_head) buses = 4; 308 309 /* find existing buses */ 310 for (bus = 0; bus < buses; bus++) 311 { 312 /* reset status */ 313 i2c_flag_error (-1); 314 snooze(6); 315 /* init and/or stop I2C bus */ 316 i2c_bstop(bus); 317 /* check for hardware coupling of SCL and SDA -out and -in lines */ 318 snooze(6); 319 OutSCL(bus, false); 320 OutSDA(bus, true); 321 snooze(3); 322 if (InSCL(bus) || !InSDA(bus)) continue; 323 snooze(3); 324 OutSCL(bus, true); 325 OutSDA(bus, false); 326 snooze(3); 327 if (!InSCL(bus) || InSDA(bus)) continue; 328 i2c_bus[bus] = true; 329 snooze(3); 330 /* re-init bus */ 331 i2c_bstop(bus); 332 } 333 334 for (bus = 0; bus < buses; bus++) 335 { 336 if (i2c_bus[bus]) 337 { 338 LOG(4,("I2C: bus #%d wiring check: passed\n", bus)); 339 result = B_OK; 340 } 341 else 342 LOG(4,("I2C: bus #%d wiring check: failed\n", bus)); 343 } 344 345 //i2c_TestEDID(); 346 i2c_DetectScreens(); 347 LOG(4,("I2C: dumping EDID specs for connector 1:\n")); 348 i2c_DumpSpecsEDID(&si->ps.con1_screen); 349 LOG(4,("I2C: dumping EDID specs for connector 2:\n")); 350 i2c_DumpSpecsEDID(&si->ps.con2_screen); 351 352 return result; 353 } 354 355 /*** DDC/EDID library use ***/ 356 typedef struct { 357 uint32 port; 358 } ddc_port_info; 359 360 /* Dump EDID info in driver's logfile */ 361 static void 362 i2c_DumpEDID(edid1_info *edid) 363 { 364 int i, j; 365 366 LOG(4,("Vendor: %s\n", edid->vendor.manufacturer)); 367 LOG(4,("Product ID: %d\n", (int)edid->vendor.prod_id)); 368 LOG(4,("Serial #: %d\n", (int)edid->vendor.serial)); 369 LOG(4,("Produced in week/year: %d/%d\n", edid->vendor.week, edid->vendor.year)); 370 371 LOG(4,("EDID version: %d.%d\n", edid->version.version, edid->version.revision)); 372 373 LOG(4,("Type: %s\n", edid->display.input_type ? "Digital" : "Analog")); 374 LOG(4,("Size: %d cm x %d cm\n", edid->display.h_size, edid->display.v_size)); 375 LOG(4,("Gamma=%.3f\n", (edid->display.gamma + 100) / 100.0)); 376 LOG(4,("White (X,Y)=(%.3f,%.3f)\n", edid->display.white_x / 1024.0, 377 edid->display.white_y / 1024.0)); 378 379 LOG(4,("Supported Future Video Modes:\n")); 380 for (i = 0; i < EDID1_NUM_STD_TIMING; ++i) { 381 if (edid->std_timing[i].h_size <= 256) 382 continue; 383 384 LOG(4,("%dx%d@%dHz (id=%d)\n", 385 edid->std_timing[i].h_size, edid->std_timing[i].v_size, 386 edid->std_timing[i].refresh, edid->std_timing[i].id)); 387 } 388 389 LOG(4,("Supported VESA Video Modes:\n")); 390 if (edid->established_timing.res_720x400x70) 391 LOG(4,("720x400@70\n")); 392 if (edid->established_timing.res_720x400x88) 393 LOG(4,("720x400@88\n")); 394 if (edid->established_timing.res_640x480x60) 395 LOG(4,("640x480@60\n")); 396 if (edid->established_timing.res_640x480x67) 397 LOG(4,("640x480x67\n")); 398 if (edid->established_timing.res_640x480x72) 399 LOG(4,("640x480x72\n")); 400 if (edid->established_timing.res_640x480x75) 401 LOG(4,("640x480x75\n")); 402 if (edid->established_timing.res_800x600x56) 403 LOG(4,("800x600@56\n")); 404 if (edid->established_timing.res_800x600x60) 405 LOG(4,("800x600@60\n")); 406 407 if (edid->established_timing.res_800x600x72) 408 LOG(4,("800x600@72\n")); 409 if (edid->established_timing.res_800x600x75) 410 LOG(4,("800x600@75\n")); 411 if (edid->established_timing.res_832x624x75) 412 LOG(4,("832x624@75\n")); 413 if (edid->established_timing.res_1024x768x87i) 414 LOG(4,("1024x768@87 interlaced\n")); 415 if (edid->established_timing.res_1024x768x60) 416 LOG(4,("1024x768@60\n")); 417 if (edid->established_timing.res_1024x768x70) 418 LOG(4,("1024x768@70\n")); 419 if (edid->established_timing.res_1024x768x75) 420 LOG(4,("1024x768@75\n")); 421 if (edid->established_timing.res_1280x1024x75) 422 LOG(4,("1280x1024@75\n")); 423 424 if (edid->established_timing.res_1152x870x75) 425 LOG(4,("1152x870@75\n")); 426 427 for (i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) { 428 edid1_detailed_monitor *monitor = &edid->detailed_monitor[i]; 429 430 switch(monitor->monitor_desc_type) { 431 case EDID1_SERIAL_NUMBER: 432 LOG(4,("Serial Number: %s\n", monitor->data.serial_number)); 433 break; 434 435 case EDID1_ASCII_DATA: 436 LOG(4,(" %s\n", monitor->data.serial_number)); 437 break; 438 439 case EDID1_MONITOR_RANGES: 440 { 441 edid1_monitor_range monitor_range = monitor->data.monitor_range; 442 443 LOG(4,("Horizontal frequency range = %d..%d kHz\n", 444 monitor_range.min_h, monitor_range.max_h)); 445 LOG(4,("Vertical frequency range = %d..%d Hz\n", 446 monitor_range.min_v, monitor_range.max_v)); 447 LOG(4,("Maximum pixel clock = %d MHz\n", (uint16)monitor_range.max_clock * 10)); 448 break; 449 } 450 451 case EDID1_MONITOR_NAME: 452 LOG(4,("Monitor Name: %s\n", monitor->data.monitor_name)); 453 break; 454 455 case EDID1_ADD_COLOUR_POINTER: 456 { 457 for (j = 0; j < EDID1_NUM_EXTRA_WHITEPOINTS; ++j) { 458 edid1_whitepoint *whitepoint = &monitor->data.whitepoint[j]; 459 460 if (whitepoint->index == 0) 461 continue; 462 463 LOG(4,("Additional whitepoint: (X,Y)=(%f,%f) gamma=%f index=%i\n", 464 whitepoint->white_x / 1024.0, 465 whitepoint->white_y / 1024.0, 466 (whitepoint->gamma + 100) / 100.0, 467 whitepoint->index)); 468 } 469 break; 470 } 471 472 case EDID1_ADD_STD_TIMING: 473 { 474 for (j = 0; j < EDID1_NUM_EXTRA_STD_TIMING; ++j) { 475 edid1_std_timing *timing = &monitor->data.std_timing[j]; 476 477 if (timing->h_size <= 256) 478 continue; 479 480 LOG(4,("%dx%d@%dHz (id=%d)\n", 481 timing->h_size, timing->v_size, 482 timing->refresh, timing->id)); 483 } 484 break; 485 } 486 487 case EDID1_IS_DETAILED_TIMING: 488 { 489 edid1_detailed_timing *timing = &monitor->data.detailed_timing; 490 491 LOG(4,("Additional Video Mode:\n")); 492 LOG(4,("clock=%f MHz\n", timing->pixel_clock / 100.0)); 493 LOG(4,("h: (%d, %d, %d, %d)\n", 494 timing->h_active, timing->h_active + timing->h_sync_off, 495 timing->h_active + timing->h_sync_off + timing->h_sync_width, 496 timing->h_active + timing->h_blank)); 497 LOG(4,("v: (%d, %d, %d, %d)\n", 498 timing->v_active, timing->v_active + timing->v_sync_off, 499 timing->v_active + timing->v_sync_off + timing->v_sync_width, 500 timing->v_active + timing->v_blank)); 501 LOG(4,("size: %.1f cm x %.1f cm\n", 502 timing->h_size / 10.0, timing->v_size / 10.0)); 503 LOG(4,("border: %.1f cm x %.1f cm\n", 504 timing->h_border / 10.0, timing->v_border / 10.0)); 505 break; 506 } 507 } 508 } 509 } 510 511 /* callback for getting signals from I2C bus */ 512 static status_t 513 get_signals(void *cookie, int *clk, int *data) 514 { 515 ddc_port_info *info = (ddc_port_info *)cookie; 516 517 *clk = *data = 0x0000; 518 if (InSCL(info->port)) *clk = 0x0001; 519 if (InSDA(info->port)) *data = 0x0001; 520 521 return B_OK; 522 } 523 524 /* callback for setting signals on I2C bus */ 525 static status_t 526 set_signals(void *cookie, int clk, int data) 527 { 528 ddc_port_info *info = (ddc_port_info *)cookie; 529 530 if (clk) 531 OutSCL(info->port, true); 532 else 533 OutSCL(info->port, false); 534 535 if (data) 536 OutSDA(info->port, true); 537 else 538 OutSDA(info->port, false); 539 540 return B_OK; 541 } 542 543 /* Read EDID information from monitor via the display data channel (DDC) */ 544 static status_t 545 i2c_ReadEDID(uint8 BusNR, edid1_info *edid) 546 { 547 i2c_bus bus; 548 ddc_port_info info; 549 550 info.port = BusNR; 551 552 bus.cookie = &info; 553 bus.set_signals = &set_signals; 554 bus.get_signals = &get_signals; 555 ddc2_init_timing(&bus); 556 557 /* select GPU I/O pins set */ 558 i2c_select_bus_set(BusNR & 0x02); 559 560 /* enable access to primary head */ 561 set_crtc_owner(0); 562 563 if (ddc2_read_edid1(&bus, edid, NULL, NULL) == B_OK) { 564 LOG(4,("I2C: EDID succesfully read from monitor at bus %d\n", BusNR)); 565 LOG(4,("I2C: EDID dump follows (bus %d):\n", BusNR)); 566 i2c_DumpEDID(edid); 567 LOG(4,("I2C: end EDID dump (bus %d).\n", BusNR)); 568 } else { 569 LOG(4,("I2C: reading EDID failed at bus %d!\n", BusNR)); 570 return B_ERROR; 571 } 572 573 return B_OK; 574 } 575 576 void i2c_TestEDID(void) 577 { 578 uint8 bus; 579 edid1_info edid; 580 bool *i2c_bus = &(si->ps.i2c_bus0); 581 582 /* test wired bus(es) */ 583 for (bus = 0; bus < 4; bus++) { 584 if (i2c_bus[bus]) 585 i2c_ReadEDID(bus, &edid); 586 } 587 } 588 589 static status_t 590 i2c_ExtractSpecsEDID(edid1_info* edid, edid_specs* specs) 591 { 592 uint32 i; 593 edid1_detailed_timing edid_timing; 594 595 specs->have_edid = false; 596 specs->timing.h_display = 0; 597 specs->timing.v_display = 0; 598 599 /* find the optimum (native) modeline */ 600 for (i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) { 601 switch(edid->detailed_monitor[i].monitor_desc_type) { 602 case EDID1_IS_DETAILED_TIMING: 603 // TODO: handle flags correctly! 604 edid_timing = edid->detailed_monitor[i].data.detailed_timing; 605 606 if (edid_timing.pixel_clock <= 0/* || edid_timing.sync != 3*/) 607 break; 608 609 /* we want the optimum (native) modeline only, widescreen if possible. 610 * So only check for horizontal display, not for vertical display. */ 611 if (edid_timing.h_active <= specs->timing.h_display) 612 break; 613 614 specs->timing.pixel_clock = edid_timing.pixel_clock * 10; 615 specs->timing.h_display = edid_timing.h_active; 616 specs->timing.h_sync_start = edid_timing.h_active + edid_timing.h_sync_off; 617 specs->timing.h_sync_end = specs->timing.h_sync_start + edid_timing.h_sync_width; 618 specs->timing.h_total = specs->timing.h_display + edid_timing.h_blank; 619 specs->timing.v_display = edid_timing.v_active; 620 specs->timing.v_sync_start = edid_timing.v_active + edid_timing.v_sync_off; 621 specs->timing.v_sync_end = specs->timing.v_sync_start + edid_timing.v_sync_width; 622 specs->timing.v_total = specs->timing.v_display + edid_timing.v_blank; 623 specs->timing.flags = 0; 624 if (edid_timing.sync == 3) { 625 if (edid_timing.misc & 1) 626 specs->timing.flags |= B_POSITIVE_HSYNC; 627 if (edid_timing.misc & 2) 628 specs->timing.flags |= B_POSITIVE_VSYNC; 629 } 630 if (edid_timing.interlaced) 631 specs->timing.flags |= B_TIMING_INTERLACED; 632 break; 633 } 634 } 635 636 /* check if we actually got a modeline */ 637 if (!specs->timing.h_display || !specs->timing.v_display) return B_ERROR; 638 639 /* we succesfully fetched the specs we need */ 640 specs->have_edid = true; 641 642 /* determine screen aspect ratio */ 643 specs->aspect = 644 (specs->timing.h_display / ((float)specs->timing.v_display)); 645 646 /* determine connection type */ 647 specs->digital = false; 648 if (edid->display.input_type) specs->digital = true; 649 650 return B_OK; 651 } 652 653 /* Dump EDID info in driver's logfile */ 654 static void 655 i2c_DumpSpecsEDID(edid_specs* specs) 656 { 657 LOG(4,("I2C: specsEDID: have_edid: %s\n", specs->have_edid ? "True" : "False")); 658 if (!specs->have_edid) return; 659 LOG(4,("I2C: specsEDID: timing.pixel_clock %.3f Mhz\n", specs->timing.pixel_clock / 1000.0)); 660 LOG(4,("I2C: specsEDID: timing.h_display %d\n", specs->timing.h_display)); 661 LOG(4,("I2C: specsEDID: timing.h_sync_start %d\n", specs->timing.h_sync_start)); 662 LOG(4,("I2C: specsEDID: timing.h_sync_end %d\n", specs->timing.h_sync_end)); 663 LOG(4,("I2C: specsEDID: timing.h_total %d\n", specs->timing.h_total)); 664 LOG(4,("I2C: specsEDID: timing.v_display %d\n", specs->timing.v_display)); 665 LOG(4,("I2C: specsEDID: timing.v_sync_start %d\n", specs->timing.v_sync_start)); 666 LOG(4,("I2C: specsEDID: timing.v_sync_end %d\n", specs->timing.v_sync_end)); 667 LOG(4,("I2C: specsEDID: timing.v_total %d\n", specs->timing.v_total)); 668 LOG(4,("I2C: specsEDID: timing.flags $%08x\n", specs->timing.flags)); 669 LOG(4,("I2C: specsEDID: aspect: %1.2f\n", specs->aspect)); 670 LOG(4,("I2C: specsEDID: digital: %s\n", specs->digital ? "True" : "False")); 671 } 672 673 /* notes: 674 * - con1 resides closest to the mainboard on for example NV25 and NV28, while for 675 * example on NV34 con2 sits closest to the mainboard. 676 * - i2c bus0 is connected to con1, and i2c bus1 is connected to con2 on all pre-NV40 677 * architecture cards. On later cards it's vice versa. */ 678 //>>>fixme: 679 //- re-check if the latter note is true, 680 //- and check if it's dependant on the DAC cross connection switch.. 681 //- and check if analog or digital connection type influences this.. 682 void i2c_DetectScreens(void) 683 { 684 edid1_info edid; 685 686 si->ps.con1_screen.have_edid = false; 687 si->ps.con2_screen.have_edid = false; 688 689 /* check existance of bus 0 */ 690 if (!si->ps.i2c_bus0) return; 691 692 /* check I2C bus 0 for an EDID capable screen */ 693 if (i2c_ReadEDID(0, &edid) == B_OK) { 694 /* fetch optimum (native) modeline */ 695 switch (si->ps.card_arch) { 696 case NV40A: 697 i2c_ExtractSpecsEDID(&edid, &si->ps.con2_screen); 698 break; 699 default: 700 i2c_ExtractSpecsEDID(&edid, &si->ps.con1_screen); 701 break; 702 } 703 } 704 705 /* check existance of bus 1 */ 706 if (!si->ps.i2c_bus1) return; 707 708 /* check I2C bus 1 for an EDID screen */ 709 if (i2c_ReadEDID(1, &edid) == B_OK) { 710 /* fetch optimum (native) modeline */ 711 switch (si->ps.card_arch) { 712 case NV40A: 713 i2c_ExtractSpecsEDID(&edid, &si->ps.con1_screen); 714 break; 715 default: 716 i2c_ExtractSpecsEDID(&edid, &si->ps.con2_screen); 717 break; 718 } 719 } 720 } 721