1/* 2 * 3 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. 4 * 5 * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz> 6 * 7 * Portions Copyright (c) 2001 Matrox Graphics Inc. 8 * 9 * Version: 1.62 2001/11/29 10 * 11 * See matroxfb_base.c for contributors. 12 * 13 */ 14 15#include "matroxfb_maven.h" 16#include "matroxfb_misc.h" 17#include "matroxfb_DAC1064.h" 18#include <linux/i2c.h> 19#include <linux/matroxfb.h> 20#include <asm/div64.h> 21#include <asm/uaccess.h> 22 23#define MAVEN_I2CID (0x1B) 24 25#define MODE_PAL MATROXFB_OUTPUT_MODE_PAL 26#define MODE_NTSC MATROXFB_OUTPUT_MODE_NTSC 27#define MODE_TV(x) (((x) == MODE_PAL) || ((x) == MODE_NTSC)) 28#define MODE_MONITOR MATROXFB_OUTPUT_MODE_MONITOR 29 30#define MGATVO_B 1 31#define MGATVO_C 2 32 33struct maven_data { 34 struct matrox_fb_info* primary_head; 35 struct i2c_client* client; 36 int mode; 37 int version; 38}; 39 40static int maven_get_reg(struct i2c_client* c, char reg) { 41 char dst; 42 struct i2c_msg msgs[] = {{ c->addr, I2C_M_REV_DIR_ADDR, sizeof(reg), ® }, 43 { c->addr, I2C_M_RD | I2C_M_NOSTART, sizeof(dst), &dst }}; 44 s32 err; 45 46 err = i2c_transfer(c->adapter, msgs, 2); 47 if (err < 0) 48 printk(KERN_INFO "ReadReg(%d) failed\n", reg); 49 return dst & 0xFF; 50} 51 52static int maven_set_reg(struct i2c_client* c, int reg, int val) { 53 s32 err; 54 55 err = i2c_smbus_write_byte_data(c, reg, val); 56 if (err) 57 printk(KERN_INFO "WriteReg(%d) failed\n", reg); 58 return err; 59} 60 61static int maven_set_reg_pair(struct i2c_client* c, int reg, int val) { 62 s32 err; 63 64 err = i2c_smbus_write_word_data(c, reg, val); 65 if (err) 66 printk(KERN_INFO "WriteRegPair(%d) failed\n", reg); 67 return err; 68} 69 70static const struct matrox_pll_features maven_pll = { 71 50000, 72 27000, 73 4, 127, 74 2, 31, 75 3 76}; 77 78struct matrox_pll_features2 { 79 unsigned int vco_freq_min; 80 unsigned int vco_freq_max; 81 unsigned int feed_div_min; 82 unsigned int feed_div_max; 83 unsigned int in_div_min; 84 unsigned int in_div_max; 85 unsigned int post_shift_max; 86}; 87 88struct matrox_pll_ctl { 89 unsigned int ref_freq; 90 unsigned int den; 91}; 92 93static const struct matrox_pll_features2 maven1000_pll = { 94 50000000, 95 300000000, 96 5, 128, 97 3, 32, 98 3 99}; 100 101static const struct matrox_pll_ctl maven_PAL = { 102 540000, 103 50 104}; 105 106static const struct matrox_pll_ctl maven_NTSC = { 107 450450, /* 27027000/60 == 27000000/59.94005994 */ 108 60 109}; 110 111static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll, 112 const struct matrox_pll_ctl* ctl, 113 unsigned int htotal, unsigned int vtotal, 114 unsigned int* in, unsigned int* feed, unsigned int* post, 115 unsigned int* h2) { 116 unsigned int besth2 = 0; 117 unsigned int fxtal = ctl->ref_freq; 118 unsigned int fmin = pll->vco_freq_min / ctl->den; 119 unsigned int fwant; 120 unsigned int p; 121 unsigned int scrlen; 122 unsigned int fmax; 123 124 DBG("PLL_calcclock") 125 126 scrlen = htotal * (vtotal - 1); 127 fwant = htotal * vtotal; 128 fmax = pll->vco_freq_max / ctl->den; 129 130 printk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n", 131 fwant, fxtal, htotal, vtotal, fmax); 132 for (p = 1; p <= pll->post_shift_max; p++) { 133 if (fwant * 2 > fmax) 134 break; 135 fwant *= 2; 136 } 137 if (fwant > fmax) 138 return 0; 139 for (; p-- > 0; fwant >>= 1) { 140 unsigned int m; 141 142 if (fwant < fmin) break; 143 for (m = pll->in_div_min; m <= pll->in_div_max; m++) { 144 unsigned int n; 145 unsigned int dvd; 146 unsigned int ln; 147 148 n = (fwant * m) / fxtal; 149 if (n < pll->feed_div_min) 150 continue; 151 if (n > pll->feed_div_max) 152 break; 153 154 ln = fxtal * n; 155 dvd = m << p; 156 157 if (ln % dvd) 158 continue; 159 ln = ln / dvd; 160 161 if (ln < scrlen + 2) 162 continue; 163 ln = ln - scrlen; 164 if (ln > htotal) 165 continue; 166 printk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln); 167 if (ln > besth2) { 168 printk(KERN_DEBUG "Better...\n"); 169 *h2 = besth2 = ln; 170 *post = p; 171 *in = m; 172 *feed = n; 173 } 174 } 175 } 176 if (besth2 < 2) 177 return 0; 178 dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant); 179 return fxtal * (*feed) / (*in) * ctl->den; 180} 181 182static unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl, 183 unsigned int htotal, unsigned int vtotal, 184 unsigned int* in, unsigned int* feed, unsigned int* post, 185 unsigned int* htotal2) { 186 unsigned int fvco; 187 unsigned int p; 188 189 fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2); 190 if (!fvco) 191 return -EINVAL; 192 p = (1 << p) - 1; 193 if (fvco <= 100000000) 194 ; 195 else if (fvco <= 140000000) 196 p |= 0x08; 197 else if (fvco <= 180000000) 198 p |= 0x10; 199 else 200 p |= 0x18; 201 *post = p; 202 return 0; 203} 204 205static void DAC1064_calcclock(unsigned int freq, unsigned int fmax, 206 unsigned int* in, unsigned int* feed, unsigned int* post) { 207 unsigned int fvco; 208 unsigned int p; 209 210 fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p); 211 p = (1 << p) - 1; 212 if (fvco <= 100000) 213 ; 214 else if (fvco <= 140000) 215 p |= 0x08; 216 else if (fvco <= 180000) 217 p |= 0x10; 218 else 219 p |= 0x18; 220 *post = p; 221 return; 222} 223 224static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) { 225 static struct mavenregs palregs = { { 226 0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */ 227 0x00, 228 0x00, /* ? not written */ 229 0x00, /* modified by code (F9 written...) */ 230 0x00, /* ? not written */ 231 0x7E, /* 08 */ 232 0x44, /* 09 */ 233 0x9C, /* 0A */ 234 0x2E, /* 0B */ 235 0x21, /* 0C */ 236 0x00, /* ? not written */ 237 0x3F, 0x03, /* 0E-0F */ 238 0x3F, 0x03, /* 10-11 */ 239 0x1A, /* 12 */ 240 0x2A, /* 13 */ 241 0x1C, 0x3D, 0x14, /* 14-16 */ 242 0x9C, 0x01, /* 17-18 */ 243 0x00, /* 19 */ 244 0xFE, /* 1A */ 245 0x7E, /* 1B */ 246 0x60, /* 1C */ 247 0x05, /* 1D */ 248 0x89, 0x03, /* 1E-1F */ 249 0x72, /* 20 */ 250 0x07, /* 21 */ 251 0x72, /* 22 */ 252 0x00, /* 23 */ 253 0x00, /* 24 */ 254 0x00, /* 25 */ 255 0x08, /* 26 */ 256 0x04, /* 27 */ 257 0x00, /* 28 */ 258 0x1A, /* 29 */ 259 0x55, 0x01, /* 2A-2B */ 260 0x26, /* 2C */ 261 0x07, 0x7E, /* 2D-2E */ 262 0x02, 0x54, /* 2F-30 */ 263 0xB0, 0x00, /* 31-32 */ 264 0x14, /* 33 */ 265 0x49, /* 34 */ 266 0x00, /* 35 written multiple times */ 267 0x00, /* 36 not written */ 268 0xA3, /* 37 */ 269 0xC8, /* 38 */ 270 0x22, /* 39 */ 271 0x02, /* 3A */ 272 0x22, /* 3B */ 273 0x3F, 0x03, /* 3C-3D */ 274 0x00, /* 3E written multiple times */ 275 0x00, /* 3F not written */ 276 }, MODE_PAL, 625, 50 }; 277 static struct mavenregs ntscregs = { { 278 0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */ 279 0x00, 280 0x00, /* ? not written */ 281 0x00, /* modified by code (F9 written...) */ 282 0x00, /* ? not written */ 283 0x7E, /* 08 */ 284 0x43, /* 09 */ 285 0x7E, /* 0A */ 286 0x3D, /* 0B */ 287 0x00, /* 0C */ 288 0x00, /* ? not written */ 289 0x41, 0x00, /* 0E-0F */ 290 0x3C, 0x00, /* 10-11 */ 291 0x17, /* 12 */ 292 0x21, /* 13 */ 293 0x1B, 0x1B, 0x24, /* 14-16 */ 294 0x83, 0x01, /* 17-18 */ 295 0x00, /* 19 */ 296 0x0F, /* 1A */ 297 0x0F, /* 1B */ 298 0x60, /* 1C */ 299 0x05, /* 1D */ 300 0x89, 0x02, /* 1E-1F */ 301 0x5F, /* 20 */ 302 0x04, /* 21 */ 303 0x5F, /* 22 */ 304 0x01, /* 23 */ 305 0x02, /* 24 */ 306 0x00, /* 25 */ 307 0x0A, /* 26 */ 308 0x05, /* 27 */ 309 0x00, /* 28 */ 310 0x10, /* 29 */ 311 0xFF, 0x03, /* 2A-2B */ 312 0x24, /* 2C */ 313 0x0F, 0x78, /* 2D-2E */ 314 0x00, 0x00, /* 2F-30 */ 315 0xB2, 0x04, /* 31-32 */ 316 0x14, /* 33 */ 317 0x02, /* 34 */ 318 0x00, /* 35 written multiple times */ 319 0x00, /* 36 not written */ 320 0xA3, /* 37 */ 321 0xC8, /* 38 */ 322 0x15, /* 39 */ 323 0x05, /* 3A */ 324 0x3B, /* 3B */ 325 0x3C, 0x00, /* 3C-3D */ 326 0x00, /* 3E written multiple times */ 327 0x00, /* never written */ 328 }, MODE_NTSC, 525, 60 }; 329 330 if (md->mode & MODE_PAL) 331 *data = palregs; 332 else 333 *data = ntscregs; 334 335 data->regs[0x93] = 0xA2; 336 337 /* gamma correction registers */ 338 data->regs[0x83] = 0x00; 339 data->regs[0x84] = 0x00; 340 data->regs[0x85] = 0x00; 341 data->regs[0x86] = 0x1F; 342 data->regs[0x87] = 0x10; 343 data->regs[0x88] = 0x10; 344 data->regs[0x89] = 0x10; 345 data->regs[0x8A] = 0x64; /* 100 */ 346 data->regs[0x8B] = 0xC8; /* 200 */ 347 348 return; 349} 350 351#define LR(x) maven_set_reg(c, (x), m->regs[(x)]) 352#define LRP(x) maven_set_reg_pair(c, (x), m->regs[(x)] | (m->regs[(x)+1] << 8)) 353static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) { 354 int val; 355 356 357 maven_set_reg(c, 0x3E, 0x01); 358 maven_get_reg(c, 0x82); /* fetch oscillator state? */ 359 maven_set_reg(c, 0x8C, 0x00); 360 maven_get_reg(c, 0x94); /* get 0x82 */ 361 maven_set_reg(c, 0x94, 0xA2); 362 /* xmiscctrl */ 363 364 maven_set_reg_pair(c, 0x8E, 0x1EFF); 365 maven_set_reg(c, 0xC6, 0x01); 366 367 /* removed code... */ 368 369 maven_get_reg(c, 0x06); 370 maven_set_reg(c, 0x06, 0xF9); /* or read |= 0xF0 ? */ 371 372 /* removed code here... */ 373 374 /* real code begins here? */ 375 /* chroma subcarrier */ 376 LR(0x00); LR(0x01); LR(0x02); LR(0x03); 377 378 LR(0x04); 379 380 LR(0x2C); 381 LR(0x08); 382 LR(0x0A); 383 LR(0x09); 384 LR(0x29); 385 LRP(0x31); 386 LRP(0x17); 387 LR(0x0B); 388 LR(0x0C); 389 if (m->mode & MODE_PAL) { 390 maven_set_reg(c, 0x35, 0x10); /* ... */ 391 } else { 392 maven_set_reg(c, 0x35, 0x0F); /* ... */ 393 } 394 395 LRP(0x10); 396 397 LRP(0x0E); 398 LRP(0x1E); 399 400 LR(0x20); /* saturation #1 */ 401 LR(0x22); /* saturation #2 */ 402 LR(0x25); /* hue */ 403 LR(0x34); 404 LR(0x33); 405 LR(0x19); 406 LR(0x12); 407 LR(0x3B); 408 LR(0x13); 409 LR(0x39); 410 LR(0x1D); 411 LR(0x3A); 412 LR(0x24); 413 LR(0x14); 414 LR(0x15); 415 LR(0x16); 416 LRP(0x2D); 417 LRP(0x2F); 418 LR(0x1A); 419 LR(0x1B); 420 LR(0x1C); 421 LR(0x23); 422 LR(0x26); 423 LR(0x28); 424 LR(0x27); 425 LR(0x21); 426 LRP(0x2A); 427 if (m->mode & MODE_PAL) 428 maven_set_reg(c, 0x35, 0x1D); /* ... */ 429 else 430 maven_set_reg(c, 0x35, 0x1C); 431 432 LRP(0x3C); 433 LR(0x37); 434 LR(0x38); 435 maven_set_reg(c, 0xB3, 0x01); 436 437 maven_get_reg(c, 0xB0); /* read 0x80 */ 438 maven_set_reg(c, 0xB0, 0x08); /* ugh... */ 439 maven_get_reg(c, 0xB9); /* read 0x7C */ 440 maven_set_reg(c, 0xB9, 0x78); 441 maven_get_reg(c, 0xBF); /* read 0x00 */ 442 maven_set_reg(c, 0xBF, 0x02); 443 maven_get_reg(c, 0x94); /* read 0x82 */ 444 maven_set_reg(c, 0x94, 0xB3); 445 446 LR(0x80); /* 04 1A 91 or 05 21 91 */ 447 LR(0x81); 448 LR(0x82); 449 450 maven_set_reg(c, 0x8C, 0x20); 451 maven_get_reg(c, 0x8D); 452 maven_set_reg(c, 0x8D, 0x10); 453 454 LR(0x90); /* 4D 50 52 or 4E 05 45 */ 455 LR(0x91); 456 LR(0x92); 457 458 LRP(0x9A); /* 0049 or 004F */ 459 LRP(0x9C); /* 0004 or 0004 */ 460 LRP(0x9E); /* 0458 or 045E */ 461 LRP(0xA0); /* 05DA or 051B */ 462 LRP(0xA2); /* 00CC or 00CF */ 463 LRP(0xA4); /* 007D or 007F */ 464 LRP(0xA6); /* 007C or 007E */ 465 LRP(0xA8); /* 03CB or 03CE */ 466 LRP(0x98); /* 0000 or 0000 */ 467 LRP(0xAE); /* 0044 or 003A */ 468 LRP(0x96); /* 05DA or 051B */ 469 LRP(0xAA); /* 04BC or 046A */ 470 LRP(0xAC); /* 004D or 004E */ 471 472 LR(0xBE); 473 LR(0xC2); 474 475 maven_get_reg(c, 0x8D); 476 maven_set_reg(c, 0x8D, 0x00); 477 478 LR(0x20); /* saturation #1 */ 479 LR(0x22); /* saturation #2 */ 480 LR(0x93); /* whoops */ 481 LR(0x20); /* oh, saturation #1 again */ 482 LR(0x22); /* oh, saturation #2 again */ 483 LR(0x25); /* hue */ 484 LRP(0x0E); 485 LRP(0x1E); 486 LRP(0x0E); /* problems with memory? */ 487 LRP(0x1E); /* yes, matrox must have problems in memory area... */ 488 489 /* load gamma correction stuff */ 490 LR(0x83); 491 LR(0x84); 492 LR(0x85); 493 LR(0x86); 494 LR(0x87); 495 LR(0x88); 496 LR(0x89); 497 LR(0x8A); 498 LR(0x8B); 499 500 val = maven_get_reg(c, 0x8D); 501 val &= 0x10; /* 0x10 or anything ored with it */ 502 maven_set_reg(c, 0x8D, val); 503 504 LR(0x33); 505 LR(0x19); 506 LR(0x12); 507 LR(0x3B); 508 LR(0x13); 509 LR(0x39); 510 LR(0x1D); 511 LR(0x3A); 512 LR(0x24); 513 LR(0x14); 514 LR(0x15); 515 LR(0x16); 516 LRP(0x2D); 517 LRP(0x2F); 518 LR(0x1A); 519 LR(0x1B); 520 LR(0x1C); 521 LR(0x23); 522 LR(0x26); 523 LR(0x28); 524 LR(0x27); 525 LR(0x21); 526 LRP(0x2A); 527 if (m->mode & MODE_PAL) 528 maven_set_reg(c, 0x35, 0x1D); 529 else 530 maven_set_reg(c, 0x35, 0x1C); 531 LRP(0x3C); 532 LR(0x37); 533 LR(0x38); 534 535 maven_get_reg(c, 0xB0); 536 LR(0xB0); /* output mode */ 537 LR(0x90); 538 LR(0xBE); 539 LR(0xC2); 540 541 LRP(0x9A); 542 LRP(0xA2); 543 LRP(0x9E); 544 LRP(0xA6); 545 LRP(0xAA); 546 LRP(0xAC); 547 maven_set_reg(c, 0x3E, 0x00); 548 maven_set_reg(c, 0x95, 0x20); 549} 550 551static int maven_find_exact_clocks(unsigned int ht, unsigned int vt, 552 struct mavenregs* m) { 553 unsigned int x; 554 unsigned int err = ~0; 555 556 /* 1:1 */ 557 m->regs[0x80] = 0x0F; 558 m->regs[0x81] = 0x07; 559 m->regs[0x82] = 0x81; 560 561 for (x = 0; x < 8; x++) { 562 unsigned int a, b, c, h2; 563 unsigned int h = ht + 2 + x; 564 565 if (!matroxfb_mavenclock((m->mode & MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) { 566 unsigned int diff = h - h2; 567 568 if (diff < err) { 569 err = diff; 570 m->regs[0x80] = a - 1; 571 m->regs[0x81] = b - 1; 572 m->regs[0x82] = c | 0x80; 573 m->hcorr = h2 - 2; 574 m->htotal = h - 2; 575 } 576 } 577 } 578 return err != ~0U; 579} 580 581static inline int maven_compute_timming(struct maven_data* md, 582 struct my_timming* mt, 583 struct mavenregs* m) { 584 unsigned int tmpi; 585 unsigned int a, bv, c; 586 587 m->mode = md->mode; 588 if (MODE_TV(md->mode)) { 589 unsigned int lmargin; 590 unsigned int umargin; 591 unsigned int vslen; 592 unsigned int hcrt; 593 unsigned int slen; 594 595 maven_init_TVdata(md, m); 596 597 if (maven_find_exact_clocks(mt->HTotal, mt->VTotal, m) == 0) 598 return -EINVAL; 599 600 lmargin = mt->HTotal - mt->HSyncEnd; 601 slen = mt->HSyncEnd - mt->HSyncStart; 602 hcrt = mt->HTotal - slen - mt->delay; 603 umargin = mt->VTotal - mt->VSyncEnd; 604 vslen = mt->VSyncEnd - mt->VSyncStart; 605 606 if (m->hcorr < mt->HTotal) 607 hcrt += m->hcorr; 608 if (hcrt > mt->HTotal) 609 hcrt -= mt->HTotal; 610 if (hcrt + 2 > mt->HTotal) 611 hcrt = 0; /* or issue warning? */ 612 613 /* last (first? middle?) line in picture can have different length */ 614 /* hlen - 2 */ 615 m->regs[0x96] = m->hcorr; 616 m->regs[0x97] = m->hcorr >> 8; 617 /* ... */ 618 m->regs[0x98] = 0x00; m->regs[0x99] = 0x00; 619 /* hblanking end */ 620 m->regs[0x9A] = lmargin; /* 100% */ 621 m->regs[0x9B] = lmargin >> 8; /* 100% */ 622 /* who knows */ 623 m->regs[0x9C] = 0x04; 624 m->regs[0x9D] = 0x00; 625 /* htotal - 2 */ 626 m->regs[0xA0] = m->htotal; 627 m->regs[0xA1] = m->htotal >> 8; 628 /* vblanking end */ 629 m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1; /* stop vblanking */ 630 m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8; 631 /* something end... [A6]+1..[A8] */ 632 if (md->version == MGATVO_B) { 633 m->regs[0xA4] = 0x04; 634 m->regs[0xA5] = 0x00; 635 } else { 636 m->regs[0xA4] = 0x01; 637 m->regs[0xA5] = 0x00; 638 } 639 /* something start... 0..[A4]-1 */ 640 m->regs[0xA6] = 0x00; 641 m->regs[0xA7] = 0x00; 642 /* vertical line count - 1 */ 643 m->regs[0xA8] = mt->VTotal - 1; 644 m->regs[0xA9] = (mt->VTotal - 1) >> 8; 645 /* horizontal vidrst pos */ 646 m->regs[0xAA] = hcrt; /* 0 <= hcrt <= htotal - 2 */ 647 m->regs[0xAB] = hcrt >> 8; 648 /* vertical vidrst pos */ 649 m->regs[0xAC] = mt->VTotal - 2; 650 m->regs[0xAD] = (mt->VTotal - 2) >> 8; 651 /* moves picture up/down and so on... */ 652 m->regs[0xAE] = 0x01; /* Fix this... 0..VTotal */ 653 m->regs[0xAF] = 0x00; 654 { 655 int hdec; 656 int hlen; 657 unsigned int ibmin = 4 + lmargin + mt->HDisplay; 658 unsigned int ib; 659 int i; 660 661 /* Verify! */ 662 /* Where 94208 came from? */ 663 if (mt->HTotal) 664 hdec = 94208 / (mt->HTotal); 665 else 666 hdec = 0x81; 667 if (hdec > 0x81) 668 hdec = 0x81; 669 if (hdec < 0x41) 670 hdec = 0x41; 671 hdec--; 672 hlen = 98304 - 128 - ((lmargin + mt->HDisplay - 8) * hdec); 673 if (hlen < 0) 674 hlen = 0; 675 hlen = hlen >> 8; 676 if (hlen > 0xFF) 677 hlen = 0xFF; 678 /* Now we have to compute input buffer length. 679 If you want any picture, it must be between 680 4 + lmargin + xres 681 and 682 94208 / hdec 683 If you want perfect picture even on the top 684 of screen, it must be also 685 0x3C0000 * i / hdec + Q - R / hdec 686 where 687 R Qmin Qmax 688 0x07000 0x5AE 0x5BF 689 0x08000 0x5CF 0x5FF 690 0x0C000 0x653 0x67F 691 0x10000 0x6F8 0x6FF 692 */ 693 i = 1; 694 do { 695 ib = ((0x3C0000 * i - 0x8000)/ hdec + 0x05E7) >> 8; 696 i++; 697 } while (ib < ibmin); 698 if (ib >= m->htotal + 2) { 699 ib = ibmin; 700 } 701 702 m->regs[0x90] = hdec; /* < 0x40 || > 0x80 is bad... 0x80 is questionable */ 703 m->regs[0xC2] = hlen; 704 /* 'valid' input line length */ 705 m->regs[0x9E] = ib; 706 m->regs[0x9F] = ib >> 8; 707 } 708 { 709 int vdec; 710 int vlen; 711 712#define MATROX_USE64BIT_DIVIDE 713 if (mt->VTotal) { 714#ifdef MATROX_USE64BIT_DIVIDE 715 u64 f1; 716 u32 a; 717 u32 b; 718 719 a = m->vlines * (m->htotal + 2); 720 b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2; 721 722 f1 = ((u64)a) << 15; /* *32768 */ 723 do_div(f1, b); 724 vdec = f1; 725#else 726 vdec = m->vlines * 32768 / mt->VTotal; 727#endif 728 } else 729 vdec = 0x8000; 730 if (vdec > 0x8000) 731 vdec = 0x8000; 732 vlen = (vslen + umargin + mt->VDisplay) * vdec; 733 vlen = (vlen >> 16) - 146; 734 if (vlen < 0) 735 vlen = 0; 736 if (vlen > 0xFF) 737 vlen = 0xFF; 738 vdec--; 739 m->regs[0x91] = vdec; 740 m->regs[0x92] = vdec >> 8; 741 m->regs[0xBE] = vlen; 742 } 743 m->regs[0xB0] = 0x08; /* output: SVideo/Composite */ 744 return 0; 745 } 746 747 DAC1064_calcclock(mt->pixclock, 450000, &a, &bv, &c); 748 m->regs[0x80] = a; 749 m->regs[0x81] = bv; 750 m->regs[0x82] = c | 0x80; 751 752 m->regs[0xB3] = 0x01; 753 m->regs[0x94] = 0xB2; 754 755 /* htotal... */ 756 m->regs[0x96] = mt->HTotal; 757 m->regs[0x97] = mt->HTotal >> 8; 758 /* ?? */ 759 m->regs[0x98] = 0x00; 760 m->regs[0x99] = 0x00; 761 /* hsync len */ 762 tmpi = mt->HSyncEnd - mt->HSyncStart; 763 m->regs[0x9A] = tmpi; 764 m->regs[0x9B] = tmpi >> 8; 765 /* hblank end */ 766 tmpi = mt->HTotal - mt->HSyncStart; 767 m->regs[0x9C] = tmpi; 768 m->regs[0x9D] = tmpi >> 8; 769 /* hblank start */ 770 tmpi += mt->HDisplay; 771 m->regs[0x9E] = tmpi; 772 m->regs[0x9F] = tmpi >> 8; 773 /* htotal + 1 */ 774 tmpi = mt->HTotal + 1; 775 m->regs[0xA0] = tmpi; 776 m->regs[0xA1] = tmpi >> 8; 777 /* vsync?! */ 778 tmpi = mt->VSyncEnd - mt->VSyncStart - 1; 779 m->regs[0xA2] = tmpi; 780 m->regs[0xA3] = tmpi >> 8; 781 /* ignored? */ 782 tmpi = mt->VTotal - mt->VSyncStart; 783 m->regs[0xA4] = tmpi; 784 m->regs[0xA5] = tmpi >> 8; 785 /* ignored? */ 786 tmpi = mt->VTotal - 1; 787 m->regs[0xA6] = tmpi; 788 m->regs[0xA7] = tmpi >> 8; 789 /* vtotal - 1 */ 790 m->regs[0xA8] = tmpi; 791 m->regs[0xA9] = tmpi >> 8; 792 /* hor vidrst */ 793 tmpi = mt->HTotal - mt->delay; 794 m->regs[0xAA] = tmpi; 795 m->regs[0xAB] = tmpi >> 8; 796 /* vert vidrst */ 797 tmpi = mt->VTotal - 2; 798 m->regs[0xAC] = tmpi; 799 m->regs[0xAD] = tmpi >> 8; 800 /* ignored? */ 801 m->regs[0xAE] = 0x00; 802 m->regs[0xAF] = 0x00; 803 804 m->regs[0xB0] = 0x03; /* output: monitor */ 805 m->regs[0xB1] = 0xA0; /* ??? */ 806 m->regs[0x8C] = 0x20; /* must be set... */ 807 m->regs[0x8D] = 0x00; /* defaults to 0x10: test signal */ 808 m->regs[0xB9] = 0x1A; /* defaults to 0x2C: too bright */ 809 m->regs[0xBF] = 0x22; /* makes picture stable */ 810 811 return 0; 812} 813 814static inline int maven_program_timming(struct maven_data* md, 815 const struct mavenregs* m) { 816 struct i2c_client* c = md->client; 817 818 if (m->mode & MODE_MONITOR) { 819 LR(0x80); 820 LR(0x81); 821 LR(0x82); 822 823 LR(0xB3); 824 LR(0x94); 825 826 LRP(0x96); 827 LRP(0x98); 828 LRP(0x9A); 829 LRP(0x9C); 830 LRP(0x9E); 831 LRP(0xA0); 832 LRP(0xA2); 833 LRP(0xA4); 834 LRP(0xA6); 835 LRP(0xA8); 836 LRP(0xAA); 837 LRP(0xAC); 838 LRP(0xAE); 839 840 LR(0xB0); /* output: monitor */ 841 LR(0xB1); /* ??? */ 842 LR(0x8C); /* must be set... */ 843 LR(0x8D); /* defaults to 0x10: test signal */ 844 LR(0xB9); /* defaults to 0x2C: too bright */ 845 LR(0xBF); /* makes picture stable */ 846 } else { 847 maven_init_TV(c, m); 848 } 849 return 0; 850} 851 852static inline int maven_resync(struct maven_data* md) { 853 struct i2c_client* c = md->client; 854 maven_set_reg(c, 0x95, 0x20); /* start whole thing */ 855 return 0; 856} 857 858static int maven_set_output_mode(struct maven_data* md, u_int32_t arg) { 859 switch (arg) { 860 case MATROXFB_OUTPUT_MODE_PAL: 861 case MATROXFB_OUTPUT_MODE_NTSC: 862 case MATROXFB_OUTPUT_MODE_MONITOR: 863 md->mode = arg; 864 return 1; 865 } 866 return -EINVAL; 867} 868 869static int maven_get_output_mode(struct maven_data* md, u_int32_t *arg) { 870 *arg = md->mode; 871 return 0; 872} 873 874/******************************************************/ 875 876static int maven_out_compute(void* md, struct my_timming* mt) { 877#define mdinfo ((struct maven_data*)md) 878#define minfo (mdinfo->primary_head) 879 return maven_compute_timming(md, mt, &ACCESS_FBINFO(hw).maven); 880#undef minfo 881#undef mdinfo 882} 883 884static int maven_out_program(void* md) { 885#define mdinfo ((struct maven_data*)md) 886#define minfo (mdinfo->primary_head) 887 return maven_program_timming(md, &ACCESS_FBINFO(hw).maven); 888#undef minfo 889#undef mdinfo 890} 891 892static int maven_out_start(void* md) { 893 return maven_resync(md); 894} 895 896static void maven_out_incuse(void* md) { 897 if (md) 898 i2c_inc_use_client(((struct maven_data*)md)->client); 899} 900 901static void maven_out_decuse(void* md) { 902 if (md) 903 i2c_dec_use_client(((struct maven_data*)md)->client); 904} 905 906static int maven_out_set_mode(void* md, u_int32_t arg) { 907 return maven_set_output_mode(md, arg); 908} 909 910static int maven_out_get_mode(void* md, u_int32_t* arg) { 911 return maven_get_output_mode(md, arg); 912} 913 914static struct matrox_altout maven_altout = { 915 maven_out_compute, 916 maven_out_program, 917 maven_out_start, 918 maven_out_incuse, 919 maven_out_decuse, 920 maven_out_set_mode, 921 maven_out_get_mode 922}; 923 924static int maven_init_client(struct i2c_client* clnt) { 925 struct i2c_adapter* a = clnt->adapter; 926 struct maven_data* md = clnt->data; 927 struct matroxfb_dh_maven_info* m2info __attribute__((unused)) = ((struct i2c_bit_adapter*)a)->minfo; 928 MINFO_FROM(m2info->primary_dev); 929 930 md->mode = MODE_MONITOR; 931 md->primary_head = MINFO; 932 md->client = clnt; 933 down_write(&ACCESS_FBINFO(altout.lock)); 934 ACCESS_FBINFO(altout.device) = md; 935 ACCESS_FBINFO(altout.output) = &maven_altout; 936 up_write(&ACCESS_FBINFO(altout.lock)); 937 ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY; 938 if (maven_get_reg(clnt, 0xB2) < 0x14) { 939 md->version = MGATVO_B; 940 } else { 941 md->version = MGATVO_C; 942 } 943 return 0; 944} 945 946static int maven_shutdown_client(struct i2c_client* clnt) { 947 struct maven_data* md = clnt->data; 948 949 if (md->primary_head) { 950 md->primary_head->output.all &= ~MATROXFB_OUTPUT_CONN_SECONDARY; 951 md->primary_head->output.ph &= ~MATROXFB_OUTPUT_CONN_SECONDARY; 952 md->primary_head->output.sh &= ~MATROXFB_OUTPUT_CONN_SECONDARY; 953 down_write(&md->primary_head->altout.lock); 954 md->primary_head->altout.device = NULL; 955 md->primary_head->altout.output = NULL; 956 up_write(&md->primary_head->altout.lock); 957 md->primary_head = NULL; 958 } 959 return 0; 960} 961 962static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END }; 963static unsigned short normal_i2c_range[] = { MAVEN_I2CID, MAVEN_I2CID, I2C_CLIENT_END }; 964I2C_CLIENT_INSMOD; 965 966static void maven_inc_use(struct i2c_client* clnt) { 967 MOD_INC_USE_COUNT; 968} 969 970static void maven_dec_use(struct i2c_client* clnt) { 971 MOD_DEC_USE_COUNT; 972} 973 974static struct i2c_driver maven_driver; 975 976static int maven_detect_client(struct i2c_adapter* adapter, int address, unsigned short flags, 977 int kind) { 978 int err = 0; 979 struct i2c_client* new_client; 980 struct maven_data* data; 981 982 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_WORD_DATA | 983 I2C_FUNC_SMBUS_BYTE_DATA | 984 I2C_FUNC_PROTOCOL_MANGLING)) 985 goto ERROR0; 986 if (!(new_client = (struct i2c_client*)kmalloc(sizeof(struct i2c_client) + sizeof(struct maven_data), 987 GFP_KERNEL))) { 988 err = -ENOMEM; 989 goto ERROR0; 990 } 991 data = (struct maven_data*)(new_client + 1); 992 new_client->data = data; 993 new_client->addr = address; 994 new_client->adapter = adapter; 995 new_client->driver = &maven_driver; 996 new_client->flags = 0; 997 if (kind < 0) { 998 ; 999 } 1000 strcpy(new_client->name, "maven client"); 1001 if ((err = i2c_attach_client(new_client))) 1002 goto ERROR3; 1003 err = maven_init_client(new_client); 1004 if (err) 1005 goto ERROR4; 1006 return 0; 1007ERROR4:; 1008 i2c_detach_client(new_client); 1009ERROR3:; 1010 kfree(new_client); 1011ERROR0:; 1012 return err; 1013} 1014 1015static int maven_attach_adapter(struct i2c_adapter* adapter) { 1016 if (adapter->id == (I2C_ALGO_BIT | I2C_HW_B_G400)) 1017 return i2c_probe(adapter, &addr_data, &maven_detect_client); 1018 return 0; 1019} 1020 1021static int maven_detach_client(struct i2c_client* client) { 1022 int err; 1023 1024 if ((err = i2c_detach_client(client))) { 1025 printk(KERN_ERR "maven: Cannot deregister client\n"); 1026 return err; 1027 } 1028 maven_shutdown_client(client); 1029 kfree(client); 1030 return 0; 1031} 1032 1033static int maven_command(struct i2c_client* client, unsigned int cmd, void* arg) { 1034 return -ENOIOCTLCMD; /* or -EINVAL, depends on who will call this */ 1035} 1036 1037static int maven_driver_registered = 0; 1038 1039static struct i2c_driver maven_driver={ 1040 "maven", 1041 I2C_DRIVERID_MGATVO, 1042 I2C_DF_NOTIFY, 1043 maven_attach_adapter, 1044 maven_detach_client, 1045 maven_command, 1046 maven_inc_use, 1047 maven_dec_use 1048}; 1049 1050/* ************************** */ 1051 1052static int matroxfb_maven_init(void) { 1053 int err; 1054 1055 err = i2c_add_driver(&maven_driver); 1056 if (err) { 1057 printk(KERN_ERR "maven: Maven driver failed to register (%d).\n", err); 1058 return err; 1059 } 1060 maven_driver_registered = 1; 1061 return 0; 1062} 1063 1064static void matroxfb_maven_exit(void) { 1065 if (maven_driver_registered) 1066 i2c_del_driver(&maven_driver); 1067} 1068 1069MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>"); 1070MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver"); 1071MODULE_LICENSE("GPL"); 1072module_init(matroxfb_maven_init); 1073module_exit(matroxfb_maven_exit); 1074/* we do not have __setup() yet */ 1075