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