3 * \brief Hardware Acceleration for Matrox Gxx cards (backend scaler)
6 * \author Frank Mehnert <fm3@os.inf.tu-dresden.de> */
8 * (c) 2002-2009 Technische Universität Dresden
9 * This file is part of TUD:OS and distributed under the terms of the
10 * GNU General Public License 2.
11 * Please see the COPYING-GPL-2 file for details.
14 /* most stuff taken from MPlayer/vidix driver */
16 #include <l4/sys/types.h>
17 #include <l4/sys/err.h>
22 #include "matrox_regs.h"
26 static l4_addr_t mga_src_base = 0;
27 static int colkey_saved = 0;
28 static int colkey_on = 0;
29 static unsigned char colkey_color[4];
30 static unsigned char colkey_mask[4];
31 static vidix_grkey_t mga_grkey;
40 #define BPP_32_DIR 0x04
41 #define BPP_32_PAL 0x07
45 #define XKEYOPMODE 0x51
46 #define XCOLMSK0RED 0x52
47 #define XCOLMSK0GREEN 0x53
48 #define XCOLMSK0BLUE 0x54
49 #define XCOLKEY0RED 0x55
50 #define XCOLKEY0GREEN 0x56
51 #define XCOLKEY0BLUE 0x57
55 #define PALWTADD 0x3c00 // Index register for X_DATAREG port
56 #define X_DATAREG 0x3c0a
58 // Backend Scaler registers
60 #define BESGLOBCTL 0x3dc0
61 #define BESLUMACTL 0x3d40
62 #define BESPITCH 0x3d24
64 #define BESA1C3ORG 0x3d60
65 #define BESA1CORG 0x3d10
66 #define BESA1ORG 0x3d00
68 #define BESA2C3ORG 0x3d64
69 #define BESA2CORG 0x3d14
70 #define BESA2ORG 0x3d04
72 #define BESB1C3ORG 0x3d68
73 #define BESB1CORG 0x3d18
74 #define BESB1ORG 0x3d08
76 #define BESB2C3ORG 0x3d6C
77 #define BESB2CORG 0x3d1C
78 #define BESB2ORG 0x3d0C
80 #define BESHCOORD 0x3d28
81 #define BESHISCAL 0x3d30
82 #define BESHSRCEND 0x3d3C
83 #define BESHSRCLST 0x3d50
84 #define BESHSRCST 0x3d38
85 #define BESV1WGHT 0x3d48
86 #define BESV2WGHT 0x3d4c
87 #define BESV1SRCLST 0x3d54
88 #define BESV2SRCLST 0x3d58
89 #define BESVISCAL 0x3d34
90 #define BESVCOORD 0x3d2c
91 #define BESSTATUS 0x3dc4
94 /* MATROX BES registers */
97 l4_uint32_t besctl; //BES Control
98 l4_uint32_t besglobctl; //BES Global control
99 l4_uint32_t beslumactl; //Luma control (brightness and contrast)
100 l4_uint32_t bespitch; //Line pitch
102 l4_uint32_t besa1c3org; //Buffer A-1 Chroma 3 plane org
103 l4_uint32_t besa1corg; //Buffer A-1 Chroma org
104 l4_uint32_t besa1org; //Buffer A-1 Luma org
106 l4_uint32_t besa2c3org; //Buffer A-2 Chroma 3 plane org
107 l4_uint32_t besa2corg; //Buffer A-2 Chroma org
108 l4_uint32_t besa2org; //Buffer A-2 Luma org
110 l4_uint32_t besb1c3org; //Buffer B-1 Chroma 3 plane org
111 l4_uint32_t besb1corg; //Buffer B-1 Chroma org
112 l4_uint32_t besb1org; //Buffer B-1 Luma org
114 l4_uint32_t besb2c3org; //Buffer B-2 Chroma 3 plane org
115 l4_uint32_t besb2corg; //Buffer B-2 Chroma org
116 l4_uint32_t besb2org; //Buffer B-2 Luma org
118 l4_uint32_t beshcoord; //BES Horizontal coord
119 l4_uint32_t beshiscal; //BES Horizontal inverse scaling [5.14]
120 l4_uint32_t beshsrcst; //BES Horizontal source start [10.14] (for scaling)
121 l4_uint32_t beshsrcend; //BES Horizontal source ending [10.14] (for scaling)
122 l4_uint32_t beshsrclst; //BES Horizontal source last
124 l4_uint32_t besvcoord; //BES Vertical coord
125 l4_uint32_t besviscal; //BES Vertical inverse scaling [5.14]
126 l4_uint32_t besv1srclst; //BES Field 1 vertical source last position
127 l4_uint32_t besv1wght; //BES Field 1 weight start
128 l4_uint32_t besv2srclst; //BES Field 2 vertical source last position
129 l4_uint32_t besv2wght; //BES Field 2 weight start
132 static bes_registers_t regs;
136 mga_vid_write_regs(int restore)
138 //Make sure internal registers don't get updated until we're done
139 mga_outl(BESGLOBCTL, (mga_inl(VCOUNT)-1)<<16);
141 // color or coordinate keying
142 if(restore && colkey_saved)
147 // Set color key registers:
148 mga_outb(PALWTADD, XKEYOPMODE);
149 mga_outb(X_DATAREG, colkey_on);
151 mga_outb(PALWTADD, XCOLKEY0RED);
152 mga_outb(X_DATAREG, colkey_color[0]);
153 mga_outb(PALWTADD, XCOLKEY0GREEN);
154 mga_outb(X_DATAREG, colkey_color[1]);
155 mga_outb(PALWTADD, XCOLKEY0BLUE);
156 mga_outb(X_DATAREG, colkey_color[2]);
157 mga_outb(PALWTADD, X_COLKEY);
158 mga_outb(X_DATAREG, colkey_color[3]);
160 mga_outb(PALWTADD, XCOLMSK0RED);
161 mga_outb(X_DATAREG, colkey_mask[0]);
162 mga_outb(PALWTADD, XCOLMSK0GREEN);
163 mga_outb(X_DATAREG, colkey_mask[1]);
164 mga_outb(PALWTADD, XCOLMSK0BLUE);
165 mga_outb(X_DATAREG, colkey_mask[2]);
166 mga_outb(PALWTADD, XCOLMSK);
167 mga_outb(X_DATAREG, colkey_mask[3]);
169 else if(!colkey_saved)
173 // Get color key registers:
174 mga_outb(PALWTADD, XKEYOPMODE);
175 colkey_on = mga_inb(X_DATAREG) & 1;
177 mga_outb(PALWTADD, XCOLKEY0RED);
178 colkey_color[0] = mga_inb(X_DATAREG);
179 mga_outb(PALWTADD, XCOLKEY0GREEN);
180 colkey_color[1] = mga_inb(X_DATAREG);
181 mga_outb(PALWTADD, XCOLKEY0BLUE);
182 colkey_color[2] = mga_inb(X_DATAREG);
183 mga_outb(PALWTADD, X_COLKEY);
184 colkey_color[3] = mga_inb(X_DATAREG);
186 mga_outb(PALWTADD, XCOLMSK0RED);
187 colkey_mask[0] = mga_inb(X_DATAREG);
188 mga_outb(PALWTADD, XCOLMSK0GREEN);
189 colkey_mask[1] = mga_inb(X_DATAREG);
190 mga_outb(PALWTADD, XCOLMSK0BLUE);
191 colkey_mask[2] = mga_inb(X_DATAREG);
192 mga_outb(PALWTADD, XCOLMSK);
193 colkey_mask[3] = mga_inb(X_DATAREG);
198 mga_outb(PALWTADD, XKEYOPMODE);
199 mga_outb(X_DATAREG, mga_grkey.ckey.op == CKEY_TRUE);
200 if (mga_grkey.ckey.op == CKEY_TRUE)
202 l4_uint32_t r=0, g=0, b=0;
204 mga_outb(PALWTADD, XMULCTRL);
205 switch (mga_inb(X_DATAREG))
208 /* Need to look up the color index, just using
213 r = mga_grkey.ckey.red >> 3;
214 g = mga_grkey.ckey.green >> 3;
215 b = mga_grkey.ckey.blue >> 3;
219 r = mga_grkey.ckey.red >> 3;
220 g = mga_grkey.ckey.green >> 2;
221 b = mga_grkey.ckey.blue >> 3;
227 r = mga_grkey.ckey.red;
228 g = mga_grkey.ckey.green;
229 b = mga_grkey.ckey.blue;
233 // Disable color keying on alpha channel
234 mga_outb(PALWTADD, XCOLMSK);
235 mga_outb(X_DATAREG, 0x00);
236 mga_outb(PALWTADD, X_COLKEY);
237 mga_outb(X_DATAREG, 0x00);
239 // Set up color key registers
240 mga_outb(PALWTADD, XCOLKEY0RED);
241 mga_outb(X_DATAREG, r);
242 mga_outb(PALWTADD, XCOLKEY0GREEN);
243 mga_outb(X_DATAREG, g);
244 mga_outb(PALWTADD, XCOLKEY0BLUE);
245 mga_outb(X_DATAREG, b);
247 // Set up color key mask registers
248 mga_outb(PALWTADD, XCOLMSK0RED);
249 mga_outb(X_DATAREG, 0xff);
250 mga_outb(PALWTADD, XCOLMSK0GREEN);
251 mga_outb(X_DATAREG, 0xff);
252 mga_outb(PALWTADD, XCOLMSK0BLUE);
253 mga_outb(X_DATAREG, 0xff);
258 mga_outl(BESCTL, regs.besctl);
260 mga_outl(BESLUMACTL, regs.beslumactl);
261 mga_outl(BESPITCH, regs.bespitch);
262 mga_outl(BESA1ORG, regs.besa1org);
263 mga_outl(BESA1CORG, regs.besa1corg);
264 mga_outl(BESA2ORG, regs.besa2org);
265 mga_outl(BESA2CORG, regs.besa2corg);
266 mga_outl(BESB1ORG, regs.besb1org);
267 mga_outl(BESB1CORG, regs.besb1corg);
268 mga_outl(BESB2ORG, regs.besb2org);
269 mga_outl(BESB2CORG, regs.besb2corg);
272 mga_outl(BESA1C3ORG, regs.besa1c3org);
273 mga_outl(BESA2C3ORG, regs.besa2c3org);
274 mga_outl(BESB1C3ORG, regs.besb1c3org);
275 mga_outl(BESB2C3ORG, regs.besb2c3org);
277 mga_outl(BESHCOORD, regs.beshcoord);
278 mga_outl(BESHISCAL, regs.beshiscal);
279 mga_outl(BESHSRCST, regs.beshsrcst);
280 mga_outl(BESHSRCEND, regs.beshsrcend);
281 mga_outl(BESHSRCLST, regs.beshsrclst);
282 mga_outl(BESVCOORD, regs.besvcoord);
283 mga_outl(BESVISCAL, regs.besviscal);
284 mga_outl(BESV1SRCLST, regs.besv1srclst);
285 mga_outl(BESV1WGHT, regs.besv1wght);
286 mga_outl(BESV2SRCLST, regs.besv2srclst);
287 mga_outl(BESV2WGHT, regs.besv2wght);
289 //update the registers somewhere between 1 and 2 frames from now.
290 mga_outl(BESGLOBCTL, regs.besglobctl + ((mga_inb(VCOUNT)+2)<<16));
294 matrox_start_video(void)
299 matrox_stop_video(void)
302 regs.besglobctl &= ~(1<<6);
303 mga_vid_write_regs(0);
307 matrox_video_playback(vidix_playback_t *config)
310 int x, y, sw, sh, dw, dh;
311 int besleft, bestop, ifactor, ofsleft, ofstop, baseadrofs, weight, weights;
313 if ((config->num_frames < 1) || (config->num_frames > 4))
314 config->num_frames = 1;
323 config->dest.pitch.y = /*32*/16;
324 config->dest.pitch.u =
325 config->dest.pitch.v = /*16*/4;
327 if ((sw < 4) || (sh < 4) || (dw < 4) || (dh < 4))
331 switch(config->fourcc)
337 config->frame_size = ((sw + 31) & ~31) * sh
338 + (((sw + 31) & ~31) * sh) / 2;
342 config->frame_size = ((sw + 31) & ~31) * sh * 2;
348 /* make it possible to map offscreen area using L4 flexpage */
349 config->frame_size = (config->frame_size + 1024*1024 - 1) & ~(1024*1024-1);
351 config->offsets[0] = 0;
352 for (i = 1; i < config->num_frames+1; i++)
353 config->offsets[i] = i*config->frame_size;
355 config->offset.y = 0;
356 // config->offset.u = ((sw + 15) & ~15) * sh;
357 config->offset.u = ((sw + 31) & ~31) * sh;
358 // config->offset.v = config->offset.u+((sw + 15) & ~15) * sh /4;
359 config->offset.v = config->offset.u+((sw + 31) & ~31) * sh /4;
361 mga_src_base = hw_vid_mem_size - config->num_frames*config->frame_size;
362 mga_src_base &= ~(1024*1024-1); /* 1MB boundary */
364 config->dga_addr = (char*)hw_map_vid_mem_addr + mga_src_base;
366 /* for G200 set Interleaved UV planes */
368 config->flags = VID_PLAY_INTERLEAVED_UV | INTERLEAVING_UV;
372 switch(config->fourcc)
377 regs.besctl = 1 // BES enabled
378 + (0<<6) // even start polarity
379 + (1<<10) // x filtering enabled
380 + (1<<11) // y filtering enabled
381 + (1<<16) // chroma upsampling
382 + (1<<17) // 4:2:0 mode
383 + (1<<18); // dither enabled
387 regs.besctl = 1 // BES enabled
388 + (0<<6) // even start polarity
389 + (1<<10) // x filtering enabled
390 + (1<<11) // y filtering enabled
391 + (1<<16) // chroma upsampling
392 + (0<<17) // 4:2:2 mode
393 + (1<<18); // dither enabled
394 regs.besglobctl = 0; // YUY2 format selected
398 regs.besctl = 1 // BES enabled
399 + (0<<6) // even start polarity
400 + (1<<10) // x filtering enabled
401 + (1<<11) // y filtering enabled
402 + (1<<16) // chroma upsampling
403 + (0<<17) // 4:2:2 mode
404 + (1<<18); // dither enabled
405 regs.besglobctl = 1<<6; // UYVY format selected
409 //Disable contrast and brightness control
410 regs.besglobctl |= (1<<5) + (1<<7);
411 regs.beslumactl = (0x7f << 16) + (0x80<<0);
412 regs.beslumactl = 0x80<<0;
414 //Setup destination window boundaries
415 besleft = x > 0 ? x : 0;
416 bestop = y > 0 ? y : 0;
417 regs.beshcoord = (besleft<<16) + (x + dw-1);
418 regs.besvcoord = (bestop <<16) + (y + dh-1);
420 //Setup source dimensions
421 regs.beshsrclst = (sw - 1) << 16;
422 regs.bespitch = (sw + 31) & ~31;
423 // regs.bespitch = (sw + 15) & ~15;
425 //Setup horizontal scaling
426 ifactor = ((sw-1)<<14)/(dw-1);
427 ofsleft = besleft - x;
429 regs.beshiscal = ifactor<<2;
430 regs.beshsrcst = (ofsleft*ifactor)<<2;
431 regs.beshsrcend = regs.beshsrcst + (((dw - ofsleft - 1) * ifactor) << 2);
433 //Setup vertical scaling
434 ifactor = ((sh-1)<<14)/(dh-1);
437 regs.besviscal = ifactor<<2;
439 baseadrofs = ((ofstop*regs.besviscal)>>16)*regs.bespitch;
440 regs.besa1org = mga_src_base + baseadrofs;
441 regs.besa2org = mga_src_base + baseadrofs + 1*config->frame_size;
442 regs.besb1org = mga_src_base + baseadrofs + 2*config->frame_size;
443 regs.besb2org = mga_src_base + baseadrofs + 3*config->frame_size;
445 if( config->fourcc==IMGFMT_YV12
446 ||config->fourcc==IMGFMT_IYUV
447 ||config->fourcc==IMGFMT_I420)
449 // planar YUV frames:
451 baseadrofs = (((ofstop*regs.besviscal)/4)>>16)*regs.bespitch;
453 baseadrofs = (((ofstop*regs.besviscal)/2)>>16)*regs.bespitch;
455 if (config->fourcc == IMGFMT_YV12)
457 regs.besa1corg = mga_src_base + baseadrofs
458 + regs.bespitch * sh;
459 regs.besa2corg = mga_src_base + baseadrofs
460 + 1*config->frame_size + regs.bespitch * sh;
461 regs.besb1corg = mga_src_base + baseadrofs
462 + 2*config->frame_size + regs.bespitch * sh;
463 regs.besb2corg = mga_src_base + baseadrofs
464 + 3*config->frame_size + regs.bespitch * sh;
465 regs.besa1c3org = regs.besa1corg + ((regs.bespitch * sh) / 4);
466 regs.besa2c3org = regs.besa2corg + ((regs.bespitch * sh) / 4);
467 regs.besb1c3org = regs.besb1corg + ((regs.bespitch * sh) / 4);
468 regs.besb2c3org = regs.besb2corg + ((regs.bespitch * sh) / 4);
472 regs.besa1c3org = mga_src_base + baseadrofs
473 + regs.bespitch * sh;
474 regs.besa2c3org = mga_src_base + baseadrofs
475 + 1*config->frame_size + regs.bespitch * sh;
476 regs.besb1c3org = mga_src_base + baseadrofs
477 + 2*config->frame_size + regs.bespitch * sh;
478 regs.besb2c3org = mga_src_base + baseadrofs
479 + 3*config->frame_size + regs.bespitch * sh;
480 regs.besa1corg = regs.besa1c3org + ((regs.bespitch * sh) / 4);
481 regs.besa2corg = regs.besa2c3org + ((regs.bespitch * sh) / 4);
482 regs.besb1corg = regs.besb1c3org + ((regs.bespitch * sh) / 4);
483 regs.besb2corg = regs.besb2c3org + ((regs.bespitch * sh) / 4);
487 weight = ofstop * (regs.besviscal >> 2);
488 weights = weight < 0 ? 1 : 0;
490 regs.besv1wght = (weights << 16) + ((weight & 0x3FFF) << 2);
492 regs.besv1srclst = sh - 1 - (((ofstop * regs.besviscal) >> 16) & 0x03FF);
494 mga_vid_write_regs(0);
499 matrox_set_grkey(const vidix_grkey_t *grkey)
501 memcpy((void*)&mga_grkey, grkey, sizeof(vidix_grkey_t));
505 matrox_set_equalizer(const vidix_video_eq_t *eq)
507 if (eq->cap & VEQ_CAP_BRIGHTNESS)
509 regs.beslumactl &= 0xFFFF;
510 regs.beslumactl |= (eq->brightness*255/2000)<<16;
512 if (eq->cap & VEQ_CAP_CONTRAST)
514 regs.beslumactl &= 0xFFFF0000;
515 regs.beslumactl |= (128+eq->contrast*255/2000)&0xFFFF;
517 mga_outl(BESLUMACTL, regs.beslumactl);
521 matrox_vid_init(con_accel_t *accel)
523 accel->cscs_init = matrox_video_playback;
524 accel->cscs_start = matrox_start_video;
525 accel->cscs_stop = matrox_stop_video;
526 accel->cscs_grkey = matrox_set_grkey;
527 accel->caps |= ACCEL_FAST_CSCS_YV12 | ACCEL_COLOR_KEY;
531 accel->caps |= ACCEL_EQ_BRIGHTNESS | ACCEL_EQ_CONTRAST;
532 accel->cscs_eq = matrox_set_equalizer;