matroxfb_maven.c revision 847fb8aca3b79d03ef6c5f87f0843a30ed9e6627
1/* 2 * 3 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. 4 * 5 * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> 6 * 7 * Portions Copyright (c) 2001 Matrox Graphics Inc. 8 * 9 * Version: 1.65 2002/08/14 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 <linux/slab.h> 21#include <asm/div64.h> 22 23#define MGATVO_B 1 24#define MGATVO_C 2 25 26static const struct maven_gamma { 27 unsigned char reg83; 28 unsigned char reg84; 29 unsigned char reg85; 30 unsigned char reg86; 31 unsigned char reg87; 32 unsigned char reg88; 33 unsigned char reg89; 34 unsigned char reg8a; 35 unsigned char reg8b; 36} maven_gamma[] = { 37 { 131, 57, 223, 15, 117, 212, 251, 91, 156}, 38 { 133, 61, 128, 63, 180, 147, 195, 100, 180}, 39 { 131, 19, 63, 31, 50, 66, 171, 64, 176}, 40 { 0, 0, 0, 31, 16, 16, 16, 100, 200}, 41 { 8, 23, 47, 73, 147, 244, 220, 80, 195}, 42 { 22, 43, 64, 80, 147, 115, 58, 85, 168}, 43 { 34, 60, 80, 214, 147, 212, 188, 85, 167}, 44 { 45, 77, 96, 216, 147, 99, 91, 85, 159}, 45 { 56, 76, 112, 107, 147, 212, 148, 64, 144}, 46 { 65, 91, 128, 137, 147, 196, 17, 69, 148}, 47 { 72, 104, 136, 138, 147, 180, 245, 73, 147}, 48 { 87, 116, 143, 126, 16, 83, 229, 77, 144}, 49 { 95, 119, 152, 254, 244, 83, 221, 77, 151}, 50 { 100, 129, 159, 156, 244, 148, 197, 77, 160}, 51 { 105, 141, 167, 247, 244, 132, 181, 84, 166}, 52 { 105, 147, 168, 247, 244, 245, 181, 90, 170}, 53 { 120, 153, 175, 248, 212, 229, 165, 90, 180}, 54 { 119, 156, 176, 248, 244, 229, 84, 74, 160}, 55 { 119, 158, 183, 248, 244, 229, 149, 78, 165} 56}; 57 58/* Definition of the various controls */ 59struct mctl { 60 struct v4l2_queryctrl desc; 61 size_t control; 62}; 63 64#define BLMIN 0x0FF 65#define WLMAX 0x3FF 66 67static const struct mctl maven_controls[] = 68{ { { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER, 69 "brightness", 70 0, WLMAX - BLMIN, 1, 379 - BLMIN, 71 0, 72 }, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) }, 73 { { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER, 74 "contrast", 75 0, 1023, 1, 127, 76 0, 77 }, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) }, 78 { { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER, 79 "saturation", 80 0, 255, 1, 155, 81 0, 82 }, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) }, 83 { { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER, 84 "hue", 85 0, 255, 1, 0, 86 0, 87 }, offsetof(struct matrox_fb_info, altout.tvo_params.hue) }, 88 { { V4L2_CID_GAMMA, V4L2_CTRL_TYPE_INTEGER, 89 "gamma", 90 0, ARRAY_SIZE(maven_gamma) - 1, 1, 3, 91 0, 92 }, offsetof(struct matrox_fb_info, altout.tvo_params.gamma) }, 93 { { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN, 94 "test output", 95 0, 1, 1, 0, 96 0, 97 }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) }, 98 { { MATROXFB_CID_DEFLICKER, V4L2_CTRL_TYPE_INTEGER, 99 "deflicker mode", 100 0, 2, 1, 0, 101 0, 102 }, offsetof(struct matrox_fb_info, altout.tvo_params.deflicker) }, 103 104}; 105 106#define MAVCTRLS ARRAY_SIZE(maven_controls) 107 108/* Return: positive number: id found 109 -EINVAL: id not found, return failure 110 -ENOENT: id not found, create fake disabled control */ 111static int get_ctrl_id(__u32 v4l2_id) { 112 int i; 113 114 for (i = 0; i < MAVCTRLS; i++) { 115 if (v4l2_id < maven_controls[i].desc.id) { 116 if (maven_controls[i].desc.id == 0x08000000) { 117 return -EINVAL; 118 } 119 return -ENOENT; 120 } 121 if (v4l2_id == maven_controls[i].desc.id) { 122 return i; 123 } 124 } 125 return -EINVAL; 126} 127 128struct maven_data { 129 struct matrox_fb_info* primary_head; 130 struct i2c_client *client; 131 int version; 132}; 133 134static int* get_ctrl_ptr(struct maven_data* md, int idx) { 135 return (int*)((char*)(md->primary_head) + maven_controls[idx].control); 136} 137 138static int maven_get_reg(struct i2c_client* c, char reg) { 139 char dst; 140 struct i2c_msg msgs[] = {{ c->addr, I2C_M_REV_DIR_ADDR, sizeof(reg), ® }, 141 { c->addr, I2C_M_RD | I2C_M_NOSTART, sizeof(dst), &dst }}; 142 s32 err; 143 144 err = i2c_transfer(c->adapter, msgs, 2); 145 if (err < 0) 146 printk(KERN_INFO "ReadReg(%d) failed\n", reg); 147 return dst & 0xFF; 148} 149 150static int maven_set_reg(struct i2c_client* c, int reg, int val) { 151 s32 err; 152 153 err = i2c_smbus_write_byte_data(c, reg, val); 154 if (err) 155 printk(KERN_INFO "WriteReg(%d) failed\n", reg); 156 return err; 157} 158 159static int maven_set_reg_pair(struct i2c_client* c, int reg, int val) { 160 s32 err; 161 162 err = i2c_smbus_write_word_data(c, reg, val); 163 if (err) 164 printk(KERN_INFO "WriteRegPair(%d) failed\n", reg); 165 return err; 166} 167 168static const struct matrox_pll_features maven_pll = { 169 50000, 170 27000, 171 4, 127, 172 2, 31, 173 3 174}; 175 176struct matrox_pll_features2 { 177 unsigned int vco_freq_min; 178 unsigned int vco_freq_max; 179 unsigned int feed_div_min; 180 unsigned int feed_div_max; 181 unsigned int in_div_min; 182 unsigned int in_div_max; 183 unsigned int post_shift_max; 184}; 185 186struct matrox_pll_ctl { 187 unsigned int ref_freq; 188 unsigned int den; 189}; 190 191static const struct matrox_pll_features2 maven1000_pll = { 192 50000000, 193 300000000, 194 5, 128, 195 3, 32, 196 3 197}; 198 199static const struct matrox_pll_ctl maven_PAL = { 200 540000, 201 50 202}; 203 204static const struct matrox_pll_ctl maven_NTSC = { 205 450450, /* 27027000/60 == 27000000/59.94005994 */ 206 60 207}; 208 209static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll, 210 const struct matrox_pll_ctl* ctl, 211 unsigned int htotal, unsigned int vtotal, 212 unsigned int* in, unsigned int* feed, unsigned int* post, 213 unsigned int* h2) { 214 unsigned int besth2 = 0; 215 unsigned int fxtal = ctl->ref_freq; 216 unsigned int fmin = pll->vco_freq_min / ctl->den; 217 unsigned int fwant; 218 unsigned int p; 219 unsigned int scrlen; 220 unsigned int fmax; 221 222 DBG(__func__) 223 224 scrlen = htotal * (vtotal - 1); 225 fwant = htotal * vtotal; 226 fmax = pll->vco_freq_max / ctl->den; 227 228 dprintk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n", 229 fwant, fxtal, htotal, vtotal, fmax); 230 for (p = 1; p <= pll->post_shift_max; p++) { 231 if (fwant * 2 > fmax) 232 break; 233 fwant *= 2; 234 } 235 if (fwant > fmax) 236 return 0; 237 for (; p-- > 0; fwant >>= 1) { 238 unsigned int m; 239 240 if (fwant < fmin) break; 241 for (m = pll->in_div_min; m <= pll->in_div_max; m++) { 242 unsigned int n; 243 unsigned int dvd; 244 unsigned int ln; 245 246 n = (fwant * m) / fxtal; 247 if (n < pll->feed_div_min) 248 continue; 249 if (n > pll->feed_div_max) 250 break; 251 252 ln = fxtal * n; 253 dvd = m << p; 254 255 if (ln % dvd) 256 continue; 257 ln = ln / dvd; 258 259 if (ln < scrlen + 2) 260 continue; 261 ln = ln - scrlen; 262 if (ln > htotal) 263 continue; 264 dprintk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln); 265 if (ln > besth2) { 266 dprintk(KERN_DEBUG "Better...\n"); 267 *h2 = besth2 = ln; 268 *post = p; 269 *in = m; 270 *feed = n; 271 } 272 } 273 } 274 275 /* if h2/post/in/feed have not been assigned, return zero (error) */ 276 if (besth2 < 2) 277 return 0; 278 279 dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant); 280 return fxtal * (*feed) / (*in) * ctl->den; 281} 282 283static int matroxfb_mavenclock(const struct matrox_pll_ctl *ctl, 284 unsigned int htotal, unsigned int vtotal, 285 unsigned int* in, unsigned int* feed, unsigned int* post, 286 unsigned int* htotal2) { 287 unsigned int fvco; 288 unsigned int uninitialized_var(p); 289 290 fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2); 291 if (!fvco) 292 return -EINVAL; 293 p = (1 << p) - 1; 294 if (fvco <= 100000000) 295 ; 296 else if (fvco <= 140000000) 297 p |= 0x08; 298 else if (fvco <= 180000000) 299 p |= 0x10; 300 else 301 p |= 0x18; 302 *post = p; 303 return 0; 304} 305 306static void DAC1064_calcclock(unsigned int freq, unsigned int fmax, 307 unsigned int* in, unsigned int* feed, unsigned int* post) { 308 unsigned int fvco; 309 unsigned int p; 310 311 fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p); 312 p = (1 << p) - 1; 313 if (fvco <= 100000) 314 ; 315 else if (fvco <= 140000) 316 p |= 0x08; 317 else if (fvco <= 180000) 318 p |= 0x10; 319 else 320 p |= 0x18; 321 *post = p; 322 return; 323} 324 325static unsigned char maven_compute_deflicker (const struct maven_data* md) { 326 unsigned char df; 327 328 df = (md->version == MGATVO_B?0x40:0x00); 329 switch (md->primary_head->altout.tvo_params.deflicker) { 330 case 0: 331/* df |= 0x00; */ 332 break; 333 case 1: 334 df |= 0xB1; 335 break; 336 case 2: 337 df |= 0xA2; 338 break; 339 } 340 return df; 341} 342 343static void maven_compute_bwlevel (const struct maven_data* md, 344 int *bl, int *wl) { 345 const int b = md->primary_head->altout.tvo_params.brightness + BLMIN; 346 const int c = md->primary_head->altout.tvo_params.contrast; 347 348 *bl = max(b - c, BLMIN); 349 *wl = min(b + c, WLMAX); 350} 351 352static const struct maven_gamma* maven_compute_gamma (const struct maven_data* md) { 353 return maven_gamma + md->primary_head->altout.tvo_params.gamma; 354} 355 356 357static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) { 358 static struct mavenregs palregs = { { 359 0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */ 360 0x00, 361 0x00, /* ? not written */ 362 0x00, /* modified by code (F9 written...) */ 363 0x00, /* ? not written */ 364 0x7E, /* 08 */ 365 0x44, /* 09 */ 366 0x9C, /* 0A */ 367 0x2E, /* 0B */ 368 0x21, /* 0C */ 369 0x00, /* ? not written */ 370 0x3F, 0x03, /* 0E-0F */ 371 0x3F, 0x03, /* 10-11 */ 372 0x1A, /* 12 */ 373 0x2A, /* 13 */ 374 0x1C, 0x3D, 0x14, /* 14-16 */ 375 0x9C, 0x01, /* 17-18 */ 376 0x00, /* 19 */ 377 0xFE, /* 1A */ 378 0x7E, /* 1B */ 379 0x60, /* 1C */ 380 0x05, /* 1D */ 381 0x89, 0x03, /* 1E-1F */ 382 0x72, /* 20 */ 383 0x07, /* 21 */ 384 0x72, /* 22 */ 385 0x00, /* 23 */ 386 0x00, /* 24 */ 387 0x00, /* 25 */ 388 0x08, /* 26 */ 389 0x04, /* 27 */ 390 0x00, /* 28 */ 391 0x1A, /* 29 */ 392 0x55, 0x01, /* 2A-2B */ 393 0x26, /* 2C */ 394 0x07, 0x7E, /* 2D-2E */ 395 0x02, 0x54, /* 2F-30 */ 396 0xB0, 0x00, /* 31-32 */ 397 0x14, /* 33 */ 398 0x49, /* 34 */ 399 0x00, /* 35 written multiple times */ 400 0x00, /* 36 not written */ 401 0xA3, /* 37 */ 402 0xC8, /* 38 */ 403 0x22, /* 39 */ 404 0x02, /* 3A */ 405 0x22, /* 3B */ 406 0x3F, 0x03, /* 3C-3D */ 407 0x00, /* 3E written multiple times */ 408 0x00, /* 3F not written */ 409 }, MATROXFB_OUTPUT_MODE_PAL, 625, 50 }; 410 static struct mavenregs ntscregs = { { 411 0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */ 412 0x00, 413 0x00, /* ? not written */ 414 0x00, /* modified by code (F9 written...) */ 415 0x00, /* ? not written */ 416 0x7E, /* 08 */ 417 0x43, /* 09 */ 418 0x7E, /* 0A */ 419 0x3D, /* 0B */ 420 0x00, /* 0C */ 421 0x00, /* ? not written */ 422 0x41, 0x00, /* 0E-0F */ 423 0x3C, 0x00, /* 10-11 */ 424 0x17, /* 12 */ 425 0x21, /* 13 */ 426 0x1B, 0x1B, 0x24, /* 14-16 */ 427 0x83, 0x01, /* 17-18 */ 428 0x00, /* 19 */ 429 0x0F, /* 1A */ 430 0x0F, /* 1B */ 431 0x60, /* 1C */ 432 0x05, /* 1D */ 433 0x89, 0x02, /* 1E-1F */ 434 0x5F, /* 20 */ 435 0x04, /* 21 */ 436 0x5F, /* 22 */ 437 0x01, /* 23 */ 438 0x02, /* 24 */ 439 0x00, /* 25 */ 440 0x0A, /* 26 */ 441 0x05, /* 27 */ 442 0x00, /* 28 */ 443 0x10, /* 29 */ 444 0xFF, 0x03, /* 2A-2B */ 445 0x24, /* 2C */ 446 0x0F, 0x78, /* 2D-2E */ 447 0x00, 0x00, /* 2F-30 */ 448 0xB2, 0x04, /* 31-32 */ 449 0x14, /* 33 */ 450 0x02, /* 34 */ 451 0x00, /* 35 written multiple times */ 452 0x00, /* 36 not written */ 453 0xA3, /* 37 */ 454 0xC8, /* 38 */ 455 0x15, /* 39 */ 456 0x05, /* 3A */ 457 0x3B, /* 3B */ 458 0x3C, 0x00, /* 3C-3D */ 459 0x00, /* 3E written multiple times */ 460 0x00, /* never written */ 461 }, MATROXFB_OUTPUT_MODE_NTSC, 525, 60 }; 462 struct matrox_fb_info *minfo = md->primary_head; 463 464 if (minfo->outputs[1].mode == MATROXFB_OUTPUT_MODE_PAL) 465 *data = palregs; 466 else 467 *data = ntscregs; 468 469 /* Set deflicker */ 470 data->regs[0x93] = maven_compute_deflicker(md); 471 472 /* set gamma */ 473 { 474 const struct maven_gamma* g; 475 g = maven_compute_gamma(md); 476 data->regs[0x83] = g->reg83; 477 data->regs[0x84] = g->reg84; 478 data->regs[0x85] = g->reg85; 479 data->regs[0x86] = g->reg86; 480 data->regs[0x87] = g->reg87; 481 data->regs[0x88] = g->reg88; 482 data->regs[0x89] = g->reg89; 483 data->regs[0x8A] = g->reg8a; 484 data->regs[0x8B] = g->reg8b; 485 } 486 487 /* Set contrast / brightness */ 488 { 489 int bl, wl; 490 maven_compute_bwlevel (md, &bl, &wl); 491 data->regs[0x0e] = bl >> 2; 492 data->regs[0x0f] = bl & 3; 493 data->regs[0x1e] = wl >> 2; 494 data->regs[0x1f] = wl & 3; 495 } 496 497 /* Set saturation */ 498 { 499 data->regs[0x20] = 500 data->regs[0x22] = minfo->altout.tvo_params.saturation; 501 } 502 503 /* Set HUE */ 504 data->regs[0x25] = minfo->altout.tvo_params.hue; 505 return; 506} 507 508#define LR(x) maven_set_reg(c, (x), m->regs[(x)]) 509#define LRP(x) maven_set_reg_pair(c, (x), m->regs[(x)] | (m->regs[(x)+1] << 8)) 510static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) { 511 int val; 512 513 514 maven_set_reg(c, 0x3E, 0x01); 515 maven_get_reg(c, 0x82); /* fetch oscillator state? */ 516 maven_set_reg(c, 0x8C, 0x00); 517 maven_get_reg(c, 0x94); /* get 0x82 */ 518 maven_set_reg(c, 0x94, 0xA2); 519 /* xmiscctrl */ 520 521 maven_set_reg_pair(c, 0x8E, 0x1EFF); 522 maven_set_reg(c, 0xC6, 0x01); 523 524 /* removed code... */ 525 526 maven_get_reg(c, 0x06); 527 maven_set_reg(c, 0x06, 0xF9); /* or read |= 0xF0 ? */ 528 529 /* removed code here... */ 530 531 /* real code begins here? */ 532 /* chroma subcarrier */ 533 LR(0x00); LR(0x01); LR(0x02); LR(0x03); 534 535 LR(0x04); 536 537 LR(0x2C); 538 LR(0x08); 539 LR(0x0A); 540 LR(0x09); 541 LR(0x29); 542 LRP(0x31); 543 LRP(0x17); 544 LR(0x0B); 545 LR(0x0C); 546 if (m->mode == MATROXFB_OUTPUT_MODE_PAL) { 547 maven_set_reg(c, 0x35, 0x10); /* ... */ 548 } else { 549 maven_set_reg(c, 0x35, 0x0F); /* ... */ 550 } 551 552 LRP(0x10); 553 554 LRP(0x0E); 555 LRP(0x1E); 556 557 LR(0x20); /* saturation #1 */ 558 LR(0x22); /* saturation #2 */ 559 LR(0x25); /* hue */ 560 LR(0x34); 561 LR(0x33); 562 LR(0x19); 563 LR(0x12); 564 LR(0x3B); 565 LR(0x13); 566 LR(0x39); 567 LR(0x1D); 568 LR(0x3A); 569 LR(0x24); 570 LR(0x14); 571 LR(0x15); 572 LR(0x16); 573 LRP(0x2D); 574 LRP(0x2F); 575 LR(0x1A); 576 LR(0x1B); 577 LR(0x1C); 578 LR(0x23); 579 LR(0x26); 580 LR(0x28); 581 LR(0x27); 582 LR(0x21); 583 LRP(0x2A); 584 if (m->mode == MATROXFB_OUTPUT_MODE_PAL) 585 maven_set_reg(c, 0x35, 0x1D); /* ... */ 586 else 587 maven_set_reg(c, 0x35, 0x1C); 588 589 LRP(0x3C); 590 LR(0x37); 591 LR(0x38); 592 maven_set_reg(c, 0xB3, 0x01); 593 594 maven_get_reg(c, 0xB0); /* read 0x80 */ 595 maven_set_reg(c, 0xB0, 0x08); /* ugh... */ 596 maven_get_reg(c, 0xB9); /* read 0x7C */ 597 maven_set_reg(c, 0xB9, 0x78); 598 maven_get_reg(c, 0xBF); /* read 0x00 */ 599 maven_set_reg(c, 0xBF, 0x02); 600 maven_get_reg(c, 0x94); /* read 0x82 */ 601 maven_set_reg(c, 0x94, 0xB3); 602 603 LR(0x80); /* 04 1A 91 or 05 21 91 */ 604 LR(0x81); 605 LR(0x82); 606 607 maven_set_reg(c, 0x8C, 0x20); 608 maven_get_reg(c, 0x8D); 609 maven_set_reg(c, 0x8D, 0x10); 610 611 LR(0x90); /* 4D 50 52 or 4E 05 45 */ 612 LR(0x91); 613 LR(0x92); 614 615 LRP(0x9A); /* 0049 or 004F */ 616 LRP(0x9C); /* 0004 or 0004 */ 617 LRP(0x9E); /* 0458 or 045E */ 618 LRP(0xA0); /* 05DA or 051B */ 619 LRP(0xA2); /* 00CC or 00CF */ 620 LRP(0xA4); /* 007D or 007F */ 621 LRP(0xA6); /* 007C or 007E */ 622 LRP(0xA8); /* 03CB or 03CE */ 623 LRP(0x98); /* 0000 or 0000 */ 624 LRP(0xAE); /* 0044 or 003A */ 625 LRP(0x96); /* 05DA or 051B */ 626 LRP(0xAA); /* 04BC or 046A */ 627 LRP(0xAC); /* 004D or 004E */ 628 629 LR(0xBE); 630 LR(0xC2); 631 632 maven_get_reg(c, 0x8D); 633 maven_set_reg(c, 0x8D, 0x04); 634 635 LR(0x20); /* saturation #1 */ 636 LR(0x22); /* saturation #2 */ 637 LR(0x93); /* whoops */ 638 LR(0x20); /* oh, saturation #1 again */ 639 LR(0x22); /* oh, saturation #2 again */ 640 LR(0x25); /* hue */ 641 LRP(0x0E); 642 LRP(0x1E); 643 LRP(0x0E); /* problems with memory? */ 644 LRP(0x1E); /* yes, matrox must have problems in memory area... */ 645 646 /* load gamma correction stuff */ 647 LR(0x83); 648 LR(0x84); 649 LR(0x85); 650 LR(0x86); 651 LR(0x87); 652 LR(0x88); 653 LR(0x89); 654 LR(0x8A); 655 LR(0x8B); 656 657 val = maven_get_reg(c, 0x8D); 658 val &= 0x14; /* 0x10 or anything ored with it */ 659 maven_set_reg(c, 0x8D, val); 660 661 LR(0x33); 662 LR(0x19); 663 LR(0x12); 664 LR(0x3B); 665 LR(0x13); 666 LR(0x39); 667 LR(0x1D); 668 LR(0x3A); 669 LR(0x24); 670 LR(0x14); 671 LR(0x15); 672 LR(0x16); 673 LRP(0x2D); 674 LRP(0x2F); 675 LR(0x1A); 676 LR(0x1B); 677 LR(0x1C); 678 LR(0x23); 679 LR(0x26); 680 LR(0x28); 681 LR(0x27); 682 LR(0x21); 683 LRP(0x2A); 684 if (m->mode == MATROXFB_OUTPUT_MODE_PAL) 685 maven_set_reg(c, 0x35, 0x1D); 686 else 687 maven_set_reg(c, 0x35, 0x1C); 688 LRP(0x3C); 689 LR(0x37); 690 LR(0x38); 691 692 maven_get_reg(c, 0xB0); 693 LR(0xB0); /* output mode */ 694 LR(0x90); 695 LR(0xBE); 696 LR(0xC2); 697 698 LRP(0x9A); 699 LRP(0xA2); 700 LRP(0x9E); 701 LRP(0xA6); 702 LRP(0xAA); 703 LRP(0xAC); 704 maven_set_reg(c, 0x3E, 0x00); 705 maven_set_reg(c, 0x95, 0x20); 706} 707 708static int maven_find_exact_clocks(unsigned int ht, unsigned int vt, 709 struct mavenregs* m) { 710 unsigned int x; 711 unsigned int err = ~0; 712 713 /* 1:1 */ 714 m->regs[0x80] = 0x0F; 715 m->regs[0x81] = 0x07; 716 m->regs[0x82] = 0x81; 717 718 for (x = 0; x < 8; x++) { 719 unsigned int c; 720 unsigned int uninitialized_var(a), uninitialized_var(b), 721 uninitialized_var(h2); 722 unsigned int h = ht + 2 + x; 723 724 if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) { 725 unsigned int diff = h - h2; 726 727 if (diff < err) { 728 err = diff; 729 m->regs[0x80] = a - 1; 730 m->regs[0x81] = b - 1; 731 m->regs[0x82] = c | 0x80; 732 m->hcorr = h2 - 2; 733 m->htotal = h - 2; 734 } 735 } 736 } 737 return err != ~0U; 738} 739 740static inline int maven_compute_timming(struct maven_data* md, 741 struct my_timming* mt, 742 struct mavenregs* m) { 743 unsigned int tmpi; 744 unsigned int a, bv, c; 745 struct matrox_fb_info *minfo = md->primary_head; 746 747 m->mode = minfo->outputs[1].mode; 748 if (m->mode != MATROXFB_OUTPUT_MODE_MONITOR) { 749 unsigned int lmargin; 750 unsigned int umargin; 751 unsigned int vslen; 752 unsigned int hcrt; 753 unsigned int slen; 754 755 maven_init_TVdata(md, m); 756 757 if (maven_find_exact_clocks(mt->HTotal, mt->VTotal, m) == 0) 758 return -EINVAL; 759 760 lmargin = mt->HTotal - mt->HSyncEnd; 761 slen = mt->HSyncEnd - mt->HSyncStart; 762 hcrt = mt->HTotal - slen - mt->delay; 763 umargin = mt->VTotal - mt->VSyncEnd; 764 vslen = mt->VSyncEnd - mt->VSyncStart; 765 766 if (m->hcorr < mt->HTotal) 767 hcrt += m->hcorr; 768 if (hcrt > mt->HTotal) 769 hcrt -= mt->HTotal; 770 if (hcrt + 2 > mt->HTotal) 771 hcrt = 0; /* or issue warning? */ 772 773 /* last (first? middle?) line in picture can have different length */ 774 /* hlen - 2 */ 775 m->regs[0x96] = m->hcorr; 776 m->regs[0x97] = m->hcorr >> 8; 777 /* ... */ 778 m->regs[0x98] = 0x00; m->regs[0x99] = 0x00; 779 /* hblanking end */ 780 m->regs[0x9A] = lmargin; /* 100% */ 781 m->regs[0x9B] = lmargin >> 8; /* 100% */ 782 /* who knows */ 783 m->regs[0x9C] = 0x04; 784 m->regs[0x9D] = 0x00; 785 /* htotal - 2 */ 786 m->regs[0xA0] = m->htotal; 787 m->regs[0xA1] = m->htotal >> 8; 788 /* vblanking end */ 789 m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1; /* stop vblanking */ 790 m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8; 791 /* something end... [A6]+1..[A8] */ 792 if (md->version == MGATVO_B) { 793 m->regs[0xA4] = 0x04; 794 m->regs[0xA5] = 0x00; 795 } else { 796 m->regs[0xA4] = 0x01; 797 m->regs[0xA5] = 0x00; 798 } 799 /* something start... 0..[A4]-1 */ 800 m->regs[0xA6] = 0x00; 801 m->regs[0xA7] = 0x00; 802 /* vertical line count - 1 */ 803 m->regs[0xA8] = mt->VTotal - 1; 804 m->regs[0xA9] = (mt->VTotal - 1) >> 8; 805 /* horizontal vidrst pos */ 806 m->regs[0xAA] = hcrt; /* 0 <= hcrt <= htotal - 2 */ 807 m->regs[0xAB] = hcrt >> 8; 808 /* vertical vidrst pos */ 809 m->regs[0xAC] = mt->VTotal - 2; 810 m->regs[0xAD] = (mt->VTotal - 2) >> 8; 811 /* moves picture up/down and so on... */ 812 m->regs[0xAE] = 0x01; /* Fix this... 0..VTotal */ 813 m->regs[0xAF] = 0x00; 814 { 815 int hdec; 816 int hlen; 817 unsigned int ibmin = 4 + lmargin + mt->HDisplay; 818 unsigned int ib; 819 int i; 820 821 /* Verify! */ 822 /* Where 94208 came from? */ 823 if (mt->HTotal) 824 hdec = 94208 / (mt->HTotal); 825 else 826 hdec = 0x81; 827 if (hdec > 0x81) 828 hdec = 0x81; 829 if (hdec < 0x41) 830 hdec = 0x41; 831 hdec--; 832 hlen = 98304 - 128 - ((lmargin + mt->HDisplay - 8) * hdec); 833 if (hlen < 0) 834 hlen = 0; 835 hlen = hlen >> 8; 836 if (hlen > 0xFF) 837 hlen = 0xFF; 838 /* Now we have to compute input buffer length. 839 If you want any picture, it must be between 840 4 + lmargin + xres 841 and 842 94208 / hdec 843 If you want perfect picture even on the top 844 of screen, it must be also 845 0x3C0000 * i / hdec + Q - R / hdec 846 where 847 R Qmin Qmax 848 0x07000 0x5AE 0x5BF 849 0x08000 0x5CF 0x5FF 850 0x0C000 0x653 0x67F 851 0x10000 0x6F8 0x6FF 852 */ 853 i = 1; 854 do { 855 ib = ((0x3C0000 * i - 0x8000)/ hdec + 0x05E7) >> 8; 856 i++; 857 } while (ib < ibmin); 858 if (ib >= m->htotal + 2) { 859 ib = ibmin; 860 } 861 862 m->regs[0x90] = hdec; /* < 0x40 || > 0x80 is bad... 0x80 is questionable */ 863 m->regs[0xC2] = hlen; 864 /* 'valid' input line length */ 865 m->regs[0x9E] = ib; 866 m->regs[0x9F] = ib >> 8; 867 } 868 { 869 int vdec; 870 int vlen; 871 872#define MATROX_USE64BIT_DIVIDE 873 if (mt->VTotal) { 874#ifdef MATROX_USE64BIT_DIVIDE 875 u64 f1; 876 u32 a; 877 u32 b; 878 879 a = m->vlines * (m->htotal + 2); 880 b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2; 881 882 f1 = ((u64)a) << 15; /* *32768 */ 883 do_div(f1, b); 884 vdec = f1; 885#else 886 vdec = m->vlines * 32768 / mt->VTotal; 887#endif 888 } else 889 vdec = 0x8000; 890 if (vdec > 0x8000) 891 vdec = 0x8000; 892 vlen = (vslen + umargin + mt->VDisplay) * vdec; 893 vlen = (vlen >> 16) - 146; /* FIXME: 146?! */ 894 if (vlen < 0) 895 vlen = 0; 896 if (vlen > 0xFF) 897 vlen = 0xFF; 898 vdec--; 899 m->regs[0x91] = vdec; 900 m->regs[0x92] = vdec >> 8; 901 m->regs[0xBE] = vlen; 902 } 903 m->regs[0xB0] = 0x08; /* output: SVideo/Composite */ 904 return 0; 905 } 906 907 DAC1064_calcclock(mt->pixclock, 450000, &a, &bv, &c); 908 m->regs[0x80] = a; 909 m->regs[0x81] = bv; 910 m->regs[0x82] = c | 0x80; 911 912 m->regs[0xB3] = 0x01; 913 m->regs[0x94] = 0xB2; 914 915 /* htotal... */ 916 m->regs[0x96] = mt->HTotal; 917 m->regs[0x97] = mt->HTotal >> 8; 918 /* ?? */ 919 m->regs[0x98] = 0x00; 920 m->regs[0x99] = 0x00; 921 /* hsync len */ 922 tmpi = mt->HSyncEnd - mt->HSyncStart; 923 m->regs[0x9A] = tmpi; 924 m->regs[0x9B] = tmpi >> 8; 925 /* hblank end */ 926 tmpi = mt->HTotal - mt->HSyncStart; 927 m->regs[0x9C] = tmpi; 928 m->regs[0x9D] = tmpi >> 8; 929 /* hblank start */ 930 tmpi += mt->HDisplay; 931 m->regs[0x9E] = tmpi; 932 m->regs[0x9F] = tmpi >> 8; 933 /* htotal + 1 */ 934 tmpi = mt->HTotal + 1; 935 m->regs[0xA0] = tmpi; 936 m->regs[0xA1] = tmpi >> 8; 937 /* vsync?! */ 938 tmpi = mt->VSyncEnd - mt->VSyncStart - 1; 939 m->regs[0xA2] = tmpi; 940 m->regs[0xA3] = tmpi >> 8; 941 /* ignored? */ 942 tmpi = mt->VTotal - mt->VSyncStart; 943 m->regs[0xA4] = tmpi; 944 m->regs[0xA5] = tmpi >> 8; 945 /* ignored? */ 946 tmpi = mt->VTotal - 1; 947 m->regs[0xA6] = tmpi; 948 m->regs[0xA7] = tmpi >> 8; 949 /* vtotal - 1 */ 950 m->regs[0xA8] = tmpi; 951 m->regs[0xA9] = tmpi >> 8; 952 /* hor vidrst */ 953 tmpi = mt->HTotal - mt->delay; 954 m->regs[0xAA] = tmpi; 955 m->regs[0xAB] = tmpi >> 8; 956 /* vert vidrst */ 957 tmpi = mt->VTotal - 2; 958 m->regs[0xAC] = tmpi; 959 m->regs[0xAD] = tmpi >> 8; 960 /* ignored? */ 961 m->regs[0xAE] = 0x00; 962 m->regs[0xAF] = 0x00; 963 964 m->regs[0xB0] = 0x03; /* output: monitor */ 965 m->regs[0xB1] = 0xA0; /* ??? */ 966 m->regs[0x8C] = 0x20; /* must be set... */ 967 m->regs[0x8D] = 0x04; /* defaults to 0x10: test signal */ 968 m->regs[0xB9] = 0x1A; /* defaults to 0x2C: too bright */ 969 m->regs[0xBF] = 0x22; /* makes picture stable */ 970 971 return 0; 972} 973 974static int maven_program_timming(struct maven_data* md, 975 const struct mavenregs* m) { 976 struct i2c_client *c = md->client; 977 978 if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) { 979 LR(0x80); 980 LR(0x81); 981 LR(0x82); 982 983 LR(0xB3); 984 LR(0x94); 985 986 LRP(0x96); 987 LRP(0x98); 988 LRP(0x9A); 989 LRP(0x9C); 990 LRP(0x9E); 991 LRP(0xA0); 992 LRP(0xA2); 993 LRP(0xA4); 994 LRP(0xA6); 995 LRP(0xA8); 996 LRP(0xAA); 997 LRP(0xAC); 998 LRP(0xAE); 999 1000 LR(0xB0); /* output: monitor */ 1001 LR(0xB1); /* ??? */ 1002 LR(0x8C); /* must be set... */ 1003 LR(0x8D); /* defaults to 0x10: test signal */ 1004 LR(0xB9); /* defaults to 0x2C: too bright */ 1005 LR(0xBF); /* makes picture stable */ 1006 } else { 1007 maven_init_TV(c, m); 1008 } 1009 return 0; 1010} 1011 1012static inline int maven_resync(struct maven_data* md) { 1013 struct i2c_client *c = md->client; 1014 maven_set_reg(c, 0x95, 0x20); /* start whole thing */ 1015 return 0; 1016} 1017 1018static int maven_get_queryctrl (struct maven_data* md, 1019 struct v4l2_queryctrl *p) { 1020 int i; 1021 1022 i = get_ctrl_id(p->id); 1023 if (i >= 0) { 1024 *p = maven_controls[i].desc; 1025 return 0; 1026 } 1027 if (i == -ENOENT) { 1028 static const struct v4l2_queryctrl disctrl = 1029 { .flags = V4L2_CTRL_FLAG_DISABLED }; 1030 1031 i = p->id; 1032 *p = disctrl; 1033 p->id = i; 1034 sprintf(p->name, "Ctrl #%08X", i); 1035 return 0; 1036 } 1037 return -EINVAL; 1038} 1039 1040static int maven_set_control (struct maven_data* md, 1041 struct v4l2_control *p) { 1042 int i; 1043 1044 i = get_ctrl_id(p->id); 1045 if (i < 0) return -EINVAL; 1046 1047 /* 1048 * Check if changed. 1049 */ 1050 if (p->value == *get_ctrl_ptr(md, i)) return 0; 1051 1052 /* 1053 * Check limits. 1054 */ 1055 if (p->value > maven_controls[i].desc.maximum) return -EINVAL; 1056 if (p->value < maven_controls[i].desc.minimum) return -EINVAL; 1057 1058 /* 1059 * Store new value. 1060 */ 1061 *get_ctrl_ptr(md, i) = p->value; 1062 1063 switch (p->id) { 1064 case V4L2_CID_BRIGHTNESS: 1065 case V4L2_CID_CONTRAST: 1066 { 1067 int blacklevel, whitelevel; 1068 maven_compute_bwlevel(md, &blacklevel, &whitelevel); 1069 blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8); 1070 whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8); 1071 maven_set_reg_pair(md->client, 0x0e, blacklevel); 1072 maven_set_reg_pair(md->client, 0x1e, whitelevel); 1073 } 1074 break; 1075 case V4L2_CID_SATURATION: 1076 { 1077 maven_set_reg(md->client, 0x20, p->value); 1078 maven_set_reg(md->client, 0x22, p->value); 1079 } 1080 break; 1081 case V4L2_CID_HUE: 1082 { 1083 maven_set_reg(md->client, 0x25, p->value); 1084 } 1085 break; 1086 case V4L2_CID_GAMMA: 1087 { 1088 const struct maven_gamma* g; 1089 g = maven_compute_gamma(md); 1090 maven_set_reg(md->client, 0x83, g->reg83); 1091 maven_set_reg(md->client, 0x84, g->reg84); 1092 maven_set_reg(md->client, 0x85, g->reg85); 1093 maven_set_reg(md->client, 0x86, g->reg86); 1094 maven_set_reg(md->client, 0x87, g->reg87); 1095 maven_set_reg(md->client, 0x88, g->reg88); 1096 maven_set_reg(md->client, 0x89, g->reg89); 1097 maven_set_reg(md->client, 0x8a, g->reg8a); 1098 maven_set_reg(md->client, 0x8b, g->reg8b); 1099 } 1100 break; 1101 case MATROXFB_CID_TESTOUT: 1102 { 1103 unsigned char val 1104 = maven_get_reg(md->client, 0x8d); 1105 if (p->value) val |= 0x10; 1106 else val &= ~0x10; 1107 maven_set_reg(md->client, 0x8d, val); 1108 } 1109 break; 1110 case MATROXFB_CID_DEFLICKER: 1111 { 1112 maven_set_reg(md->client, 0x93, maven_compute_deflicker(md)); 1113 } 1114 break; 1115 } 1116 1117 1118 return 0; 1119} 1120 1121static int maven_get_control (struct maven_data* md, 1122 struct v4l2_control *p) { 1123 int i; 1124 1125 i = get_ctrl_id(p->id); 1126 if (i < 0) return -EINVAL; 1127 p->value = *get_ctrl_ptr(md, i); 1128 return 0; 1129} 1130 1131/******************************************************/ 1132 1133static int maven_out_compute(void* md, struct my_timming* mt) { 1134#define mdinfo ((struct maven_data*)md) 1135#define minfo (mdinfo->primary_head) 1136 return maven_compute_timming(md, mt, &minfo->hw.maven); 1137#undef minfo 1138#undef mdinfo 1139} 1140 1141static int maven_out_program(void* md) { 1142#define mdinfo ((struct maven_data*)md) 1143#define minfo (mdinfo->primary_head) 1144 return maven_program_timming(md, &minfo->hw.maven); 1145#undef minfo 1146#undef mdinfo 1147} 1148 1149static int maven_out_start(void* md) { 1150 return maven_resync(md); 1151} 1152 1153static int maven_out_verify_mode(void* md, u_int32_t arg) { 1154 switch (arg) { 1155 case MATROXFB_OUTPUT_MODE_PAL: 1156 case MATROXFB_OUTPUT_MODE_NTSC: 1157 case MATROXFB_OUTPUT_MODE_MONITOR: 1158 return 0; 1159 } 1160 return -EINVAL; 1161} 1162 1163static int maven_out_get_queryctrl(void* md, struct v4l2_queryctrl* p) { 1164 return maven_get_queryctrl(md, p); 1165} 1166 1167static int maven_out_get_ctrl(void* md, struct v4l2_control* p) { 1168 return maven_get_control(md, p); 1169} 1170 1171static int maven_out_set_ctrl(void* md, struct v4l2_control* p) { 1172 return maven_set_control(md, p); 1173} 1174 1175static struct matrox_altout maven_altout = { 1176 .name = "Secondary output", 1177 .compute = maven_out_compute, 1178 .program = maven_out_program, 1179 .start = maven_out_start, 1180 .verifymode = maven_out_verify_mode, 1181 .getqueryctrl = maven_out_get_queryctrl, 1182 .getctrl = maven_out_get_ctrl, 1183 .setctrl = maven_out_set_ctrl, 1184}; 1185 1186static int maven_init_client(struct i2c_client* clnt) { 1187 struct maven_data* md = i2c_get_clientdata(clnt); 1188 struct matrox_fb_info *minfo = container_of(clnt->adapter, 1189 struct i2c_bit_adapter, 1190 adapter)->minfo; 1191 1192 md->primary_head = minfo; 1193 md->client = clnt; 1194 down_write(&minfo->altout.lock); 1195 minfo->outputs[1].output = &maven_altout; 1196 minfo->outputs[1].src = minfo->outputs[1].default_src; 1197 minfo->outputs[1].data = md; 1198 minfo->outputs[1].mode = MATROXFB_OUTPUT_MODE_MONITOR; 1199 up_write(&minfo->altout.lock); 1200 if (maven_get_reg(clnt, 0xB2) < 0x14) { 1201 md->version = MGATVO_B; 1202 /* Tweak some things for this old chip */ 1203 } else { 1204 md->version = MGATVO_C; 1205 } 1206 /* 1207 * Set all parameters to its initial values. 1208 */ 1209 { 1210 unsigned int i; 1211 1212 for (i = 0; i < MAVCTRLS; ++i) { 1213 *get_ctrl_ptr(md, i) = maven_controls[i].desc.default_value; 1214 } 1215 } 1216 1217 return 0; 1218} 1219 1220static int maven_shutdown_client(struct i2c_client* clnt) { 1221 struct maven_data* md = i2c_get_clientdata(clnt); 1222 1223 if (md->primary_head) { 1224 struct matrox_fb_info *minfo = md->primary_head; 1225 1226 down_write(&minfo->altout.lock); 1227 minfo->outputs[1].src = MATROXFB_SRC_NONE; 1228 minfo->outputs[1].output = NULL; 1229 minfo->outputs[1].data = NULL; 1230 minfo->outputs[1].mode = MATROXFB_OUTPUT_MODE_MONITOR; 1231 up_write(&minfo->altout.lock); 1232 md->primary_head = NULL; 1233 } 1234 return 0; 1235} 1236 1237static int maven_probe(struct i2c_client *client, 1238 const struct i2c_device_id *id) 1239{ 1240 struct i2c_adapter *adapter = client->adapter; 1241 int err = -ENODEV; 1242 struct maven_data* data; 1243 1244 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_WORD_DATA | 1245 I2C_FUNC_SMBUS_BYTE_DATA | 1246 I2C_FUNC_PROTOCOL_MANGLING)) 1247 goto ERROR0; 1248 if (!(data = kzalloc(sizeof(*data), GFP_KERNEL))) { 1249 err = -ENOMEM; 1250 goto ERROR0; 1251 } 1252 i2c_set_clientdata(client, data); 1253 err = maven_init_client(client); 1254 if (err) 1255 goto ERROR4; 1256 return 0; 1257ERROR4:; 1258 kfree(data); 1259ERROR0:; 1260 return err; 1261} 1262 1263static int maven_remove(struct i2c_client *client) 1264{ 1265 maven_shutdown_client(client); 1266 kfree(i2c_get_clientdata(client)); 1267 return 0; 1268} 1269 1270static const struct i2c_device_id maven_id[] = { 1271 { "maven", 0 }, 1272 { } 1273}; 1274MODULE_DEVICE_TABLE(i2c, maven_id); 1275 1276static struct i2c_driver maven_driver={ 1277 .driver = { 1278 .name = "maven", 1279 }, 1280 .probe = maven_probe, 1281 .remove = maven_remove, 1282 .id_table = maven_id, 1283}; 1284 1285static int __init matroxfb_maven_init(void) 1286{ 1287 return i2c_add_driver(&maven_driver); 1288} 1289 1290static void __exit matroxfb_maven_exit(void) 1291{ 1292 i2c_del_driver(&maven_driver); 1293} 1294 1295MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>"); 1296MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver"); 1297MODULE_LICENSE("GPL"); 1298module_init(matroxfb_maven_init); 1299module_exit(matroxfb_maven_exit); 1300/* we do not have __setup() yet */ 1301