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