]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4con/server/src/con_hw/matrox_vid.c
451a07f47168b4a4400fcd04403a96040bdb1fcf
[l4.git] / l4 / pkg / l4con / server / src / con_hw / matrox_vid.c
1 /*!
2  * \file        matrox_vid.c
3  * \brief       Hardware Acceleration for Matrox Gxx cards (backend scaler)
4  *
5  * \date        07/2002
6  * \author      Frank Mehnert <fm3@os.inf.tu-dresden.de> */
7 /*
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.
12  */
13
14 /* most stuff taken from MPlayer/vidix driver */
15
16 #include <l4/sys/types.h>
17 #include <l4/sys/err.h>
18 #include <string.h>
19
20 #include "init.h"
21 #include "matrox.h"
22 #include "matrox_regs.h"
23 #include "vidix.h"
24 #include "fourcc.h"
25
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;
32
33 extern int is_g400;
34
35 #define XMULCTRL      0x19
36 #define BPP_8         0x00
37 #define BPP_15        0x01
38 #define BPP_16        0x02
39 #define BPP_24        0x03
40 #define BPP_32_DIR    0x04
41 #define BPP_32_PAL    0x07
42
43 #define XCOLMSK       0x40
44 #define X_COLKEY      0x42
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
52
53 #define VCOUNT      0x1e20
54
55 #define PALWTADD    0x3c00 // Index register for X_DATAREG port
56 #define X_DATAREG   0x3c0a
57
58 // Backend Scaler registers
59 #define BESCTL      0x3d20
60 #define BESGLOBCTL  0x3dc0
61 #define BESLUMACTL  0x3d40
62 #define BESPITCH    0x3d24
63
64 #define BESA1C3ORG  0x3d60
65 #define BESA1CORG   0x3d10
66 #define BESA1ORG    0x3d00
67
68 #define BESA2C3ORG  0x3d64 
69 #define BESA2CORG   0x3d14
70 #define BESA2ORG    0x3d04
71
72 #define BESB1C3ORG  0x3d68
73 #define BESB1CORG   0x3d18
74 #define BESB1ORG    0x3d08
75
76 #define BESB2C3ORG  0x3d6C
77 #define BESB2CORG   0x3d1C
78 #define BESB2ORG    0x3d0C
79
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
92
93
94 /* MATROX BES registers */
95 typedef struct
96 {
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
101   
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
105   
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
109   
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
113   
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
117   
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 
123   
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
130 } bes_registers_t;
131
132 static bes_registers_t regs;
133
134
135 static void
136 mga_vid_write_regs(int restore)
137 {
138   //Make sure internal registers don't get updated until we're done
139   mga_outl(BESGLOBCTL, (mga_inl(VCOUNT)-1)<<16);
140
141   // color or coordinate keying
142   if(restore && colkey_saved)
143     {
144       // restore it
145       colkey_saved=0;
146
147       // Set color key registers:
148       mga_outb(PALWTADD, XKEYOPMODE);
149       mga_outb(X_DATAREG, colkey_on);
150
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]);
159       
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]);
168     } 
169   else if(!colkey_saved)
170     {
171       // save it
172       colkey_saved=1;
173       // Get color key registers:
174       mga_outb(PALWTADD, XKEYOPMODE);
175       colkey_on = mga_inb(X_DATAREG) & 1;
176       
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);
185       
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);
194     }
195
196   if(!restore)
197     {
198       mga_outb(PALWTADD, XKEYOPMODE);
199       mga_outb(X_DATAREG, mga_grkey.ckey.op == CKEY_TRUE);
200       if (mga_grkey.ckey.op == CKEY_TRUE)
201         {
202           l4_uint32_t r=0, g=0, b=0;
203
204           mga_outb(PALWTADD, XMULCTRL);
205           switch (mga_inb(X_DATAREG)) 
206             {
207             case BPP_8:
208               /* Need to look up the color index, just using
209                  color 0 for now. */
210               break;
211               
212             case BPP_15:
213               r = mga_grkey.ckey.red   >> 3;
214               g = mga_grkey.ckey.green >> 3;
215               b = mga_grkey.ckey.blue  >> 3;
216               break;
217
218             case BPP_16:
219               r = mga_grkey.ckey.red   >> 3;
220               g = mga_grkey.ckey.green >> 2;
221               b = mga_grkey.ckey.blue  >> 3;
222               break;
223
224             case BPP_24:
225             case BPP_32_DIR:
226             case BPP_32_PAL:
227               r = mga_grkey.ckey.red;
228               g = mga_grkey.ckey.green;
229               b = mga_grkey.ckey.blue;
230               break;
231             }
232
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);
238
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);
246
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);
254         }
255     }
256
257   // Backend Scaler
258   mga_outl(BESCTL,    regs.besctl);
259   if(is_g400)
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);
270   if(is_g400)
271     {
272       mga_outl(BESA1C3ORG, regs.besa1c3org);
273       mga_outl(BESA2C3ORG, regs.besa2c3org);
274       mga_outl(BESB1C3ORG, regs.besb1c3org);
275       mga_outl(BESB2C3ORG, regs.besb2c3org);
276     }
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);
288   
289   //update the registers somewhere between 1 and 2 frames from now.
290   mga_outl(BESGLOBCTL,  regs.besglobctl + ((mga_inb(VCOUNT)+2)<<16));
291 }
292
293 static void
294 matrox_start_video(void)
295 {
296 }
297
298 static void
299 matrox_stop_video(void)
300 {
301   regs.besctl &= ~1;
302   regs.besglobctl &= ~(1<<6);
303   mga_vid_write_regs(0);
304 }
305
306 static int
307 matrox_video_playback(vidix_playback_t *config)
308 {
309   unsigned i;
310   int x, y, sw, sh, dw, dh;
311   int besleft, bestop, ifactor, ofsleft, ofstop, baseadrofs, weight, weights;
312
313   if ((config->num_frames < 1) || (config->num_frames > 4))
314     config->num_frames = 1;
315
316   x  = config->dest.x;
317   y  = config->dest.y;
318   sw = config->src.w;
319   sh = config->src.h;
320   dw = config->dest.w;
321   dh = config->dest.h;
322
323   config->dest.pitch.y = /*32*/16;
324   config->dest.pitch.u = 
325   config->dest.pitch.v = /*16*/4;
326
327   if ((sw < 4) || (sh < 4) || (dw < 4) || (dh < 4))
328     return -L4_EINVAL;
329
330   sw += sw & 1;
331   switch(config->fourcc)
332     {
333     case IMGFMT_I420:
334     case IMGFMT_IYUV:
335     case IMGFMT_YV12:
336       sh += sh & 1;
337       config->frame_size =  ((sw + 31) & ~31) * sh
338                          + (((sw + 31) & ~31) * sh) / 2;
339       break;
340     case IMGFMT_YUY2:
341     case IMGFMT_UYVY:
342       config->frame_size = ((sw + 31) & ~31) * sh * 2;
343       break;
344     default:
345       return -L4_EINVAL;
346     }
347
348   /* make it possible to map offscreen area using L4 flexpage */
349   config->frame_size = (config->frame_size + 1024*1024 - 1) & ~(1024*1024-1);
350
351   config->offsets[0] = 0;
352   for (i = 1; i < config->num_frames+1; i++)
353     config->offsets[i] = i*config->frame_size;
354
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;
360
361   mga_src_base = hw_vid_mem_size - config->num_frames*config->frame_size;
362   mga_src_base &= ~(1024*1024-1); /* 1MB boundary */
363
364   config->dga_addr = (char*)hw_map_vid_mem_addr + mga_src_base;
365
366   /* for G200 set Interleaved UV planes */
367   if (!is_g400)
368     config->flags = VID_PLAY_INTERLEAVED_UV | INTERLEAVING_UV;
369
370   regs.besglobctl = 0;
371
372   switch(config->fourcc)
373     {
374     case IMGFMT_YV12:
375     case IMGFMT_I420:
376     case IMGFMT_IYUV:
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
384       break;
385
386     case IMGFMT_YUY2:
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
395       break;
396
397     case IMGFMT_UYVY:
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
406       break;
407     }
408
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;
413
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);
419
420   //Setup source dimensions
421   regs.beshsrclst = (sw - 1) << 16;
422   regs.bespitch   = (sw + 31) & ~31;
423 //  regs.bespitch   = (sw + 15) & ~15; 
424
425   //Setup horizontal scaling
426   ifactor = ((sw-1)<<14)/(dw-1);
427   ofsleft = besleft - x;
428
429   regs.beshiscal = ifactor<<2;
430   regs.beshsrcst = (ofsleft*ifactor)<<2;
431   regs.beshsrcend = regs.beshsrcst + (((dw - ofsleft - 1) * ifactor) << 2);
432
433   //Setup vertical scaling
434   ifactor = ((sh-1)<<14)/(dh-1);
435   ofstop = bestop - y;
436
437   regs.besviscal = ifactor<<2;
438
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;
444
445   if(   config->fourcc==IMGFMT_YV12
446       ||config->fourcc==IMGFMT_IYUV
447       ||config->fourcc==IMGFMT_I420)
448     {
449       // planar YUV frames:
450       if (is_g400) 
451         baseadrofs = (((ofstop*regs.besviscal)/4)>>16)*regs.bespitch;
452       else 
453         baseadrofs = (((ofstop*regs.besviscal)/2)>>16)*regs.bespitch;
454
455       if (config->fourcc == IMGFMT_YV12)
456         {
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);
469         } 
470       else 
471         {
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);
484         }
485     }
486
487   weight = ofstop * (regs.besviscal >> 2);
488   weights = weight < 0 ? 1 : 0;
489   regs.besv2wght   = 
490   regs.besv1wght   = (weights << 16) + ((weight & 0x3FFF) << 2);
491   regs.besv2srclst = 
492   regs.besv1srclst = sh - 1 - (((ofstop * regs.besviscal) >> 16) & 0x03FF);
493   
494   mga_vid_write_regs(0);
495   return 0;
496 }
497
498 static void
499 matrox_set_grkey(const vidix_grkey_t *grkey)
500 {
501   memcpy((void*)&mga_grkey, grkey, sizeof(vidix_grkey_t));
502 }
503
504 static void
505 matrox_set_equalizer(const vidix_video_eq_t *eq)
506 {
507   if (eq->cap & VEQ_CAP_BRIGHTNESS)
508     {
509       regs.beslumactl &= 0xFFFF;
510       regs.beslumactl |= (eq->brightness*255/2000)<<16;
511     }
512   if (eq->cap & VEQ_CAP_CONTRAST)
513     {
514       regs.beslumactl &= 0xFFFF0000;
515       regs.beslumactl |= (128+eq->contrast*255/2000)&0xFFFF;
516     }
517   mga_outl(BESLUMACTL, regs.beslumactl);
518 }
519
520 void
521 matrox_vid_init(con_accel_t *accel)
522 {
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;
528
529   if (is_g400)
530     {
531       accel->caps   |= ACCEL_EQ_BRIGHTNESS | ACCEL_EQ_CONTRAST;
532       accel->cscs_eq = matrox_set_equalizer;
533     }
534 }
535