]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4con/server/src/con_hw/ati128_vid.c
Inital import
[l4.git] / l4 / pkg / l4con / server / src / con_hw / ati128_vid.c
1 /*!
2  * \file        ati128_vid.c
3  * \brief       Hardware Acceleration for ATI Rage128 cards (backend scaler)
4  *
5  * \date        08/2003
6  * \author      Frank Mehnert <fm3@os.inf.tu-dresden.de> */
7 /*
8  * (c) 2003-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 <stdio.h>
17
18 #include <l4/sys/types.h>
19 #include <l4/sys/err.h>
20 #include <l4/sys/consts.h>
21
22 #include "init.h"
23 #include "ati128.h"
24 #include "aty128.h"
25 #include "fourcc.h"
26 #include "vidix.h"
27
28 typedef struct
29 {
30   /* base address of yuv framebuffer */
31   l4_uint32_t yuv_base;
32   l4_uint32_t fourcc;
33   /* YUV BES registers */
34   l4_uint32_t reg_load_cntl;
35   l4_uint32_t h_inc;
36   l4_uint32_t step_by;
37   l4_uint32_t y_x_start;
38   l4_uint32_t y_x_end;
39   l4_uint32_t v_inc;
40   l4_uint32_t p1_blank_lines_at_top;
41   l4_uint32_t p23_blank_lines_at_top;
42   l4_uint32_t vid_buf_pitch0_value;
43   l4_uint32_t vid_buf_pitch1_value;
44   l4_uint32_t p1_x_start_end;
45   l4_uint32_t p2_x_start_end;
46   l4_uint32_t p3_x_start_end;
47   l4_uint32_t base_addr;
48   l4_uint32_t vid_buf_base_adrs_y[10];
49   l4_uint32_t vid_buf_base_adrs_u[10];
50   l4_uint32_t vid_buf_base_adrs_v[10];
51   l4_uint32_t vid_nbufs;
52   l4_uint32_t p1_v_accum_init;
53   l4_uint32_t p1_h_accum_init;
54   l4_uint32_t p23_v_accum_init;
55   l4_uint32_t p23_h_accum_init;
56   l4_uint32_t scale_cntl;
57   l4_uint32_t exclusive_horz;
58   l4_uint32_t auto_flip_cntl;
59   l4_uint32_t key_cntl;
60   l4_uint32_t test;
61   
62   /* Configurable stuff */
63   int brightness;
64   int saturation;
65   
66   int ckey_on;
67   l4_uint32_t graphics_key_clr;
68   l4_uint32_t graphics_key_msk;
69   l4_uint32_t ckey_cntl;
70   
71 } bes_registers_t;
72
73 static bes_registers_t besr;
74 static l4_int32_t ati128_overlay_off;
75
76
77 static void
78 ati128_start_video(void)
79 {
80   l4_uint32_t bes_flags;
81
82   aty128_wait_for_fifo(1);
83   aty_st_le32(OV0_REG_LOAD_CNTL, REG_LD_CTL_LOCK);
84
85   aty128_wait_for_idle();
86   while (!(aty_ld_le32(OV0_REG_LOAD_CNTL) & REG_LD_CTL_LOCK_READBACK))
87     ;
88
89   aty128_wait_for_fifo(10);
90   aty_st_le32(FCP_CNTL,                 FCP_CNTL__GND);
91   aty_st_le32(CAP0_TRIG_CNTL,           0);
92   aty_st_le32(VID_BUFFER_CONTROL,       (1<<16) | 0x01);
93   aty_st_le32(DISP_TEST_DEBUG_CNTL,     0);
94   aty_st_le32(OV0_AUTO_FLIP_CNTL,       OV0_AUTO_FLIP_CNTL_SOFT_BUF_ODD);
95   aty_st_le32(OV0_COLOUR_CNTL,          0x00101000);
96
97   aty128_wait_for_fifo(12);
98   aty_st_le32(OV0_H_INC,                besr.h_inc);
99   aty_st_le32(OV0_STEP_BY,              besr.step_by);
100   aty_st_le32(OV0_Y_X_START,            besr.y_x_start);
101   aty_st_le32(OV0_Y_X_END,              besr.y_x_end);
102   aty_st_le32(OV0_V_INC,                besr.v_inc);
103   aty_st_le32(OV0_P1_BLANK_LINES_AT_TOP, besr.p1_blank_lines_at_top);
104   aty_st_le32(OV0_P23_BLANK_LINES_AT_TOP, besr.p23_blank_lines_at_top);
105   aty_st_le32(OV0_VID_BUF_PITCH0_VALUE, besr.vid_buf_pitch0_value);
106   aty_st_le32(OV0_VID_BUF_PITCH1_VALUE, besr.vid_buf_pitch1_value);
107   aty_st_le32(OV0_P1_X_START_END,       besr.p1_x_start_end);
108   aty_st_le32(OV0_P2_X_START_END,       besr.p2_x_start_end);
109   aty_st_le32(OV0_P3_X_START_END,       besr.p3_x_start_end);
110
111   aty128_wait_for_fifo(10);
112   aty_st_le32(OV0_VID_BUF0_BASE_ADRS,   besr.vid_buf_base_adrs_y[0]);
113   aty_st_le32(OV0_VID_BUF1_BASE_ADRS,   besr.vid_buf_base_adrs_u[0]);
114   aty_st_le32(OV0_VID_BUF2_BASE_ADRS,   besr.vid_buf_base_adrs_v[0]);
115   aty_st_le32(OV0_VID_BUF3_BASE_ADRS,   besr.vid_buf_base_adrs_y[0]);
116   aty_st_le32(OV0_VID_BUF4_BASE_ADRS,   besr.vid_buf_base_adrs_u[0]);
117   aty_st_le32(OV0_VID_BUF5_BASE_ADRS,   besr.vid_buf_base_adrs_v[0]);
118   aty_st_le32(OV0_P1_V_ACCUM_INIT,      besr.p1_v_accum_init);
119   aty_st_le32(OV0_P1_H_ACCUM_INIT,      besr.p1_h_accum_init);
120   aty_st_le32(OV0_P23_V_ACCUM_INIT,     besr.p23_v_accum_init);
121   aty_st_le32(OV0_P23_H_ACCUM_INIT,     besr.p23_h_accum_init);
122
123   bes_flags = SCALER_ENABLE
124             | SCALER_SMART_SWITCH
125             | SCALER_Y2R_TEMP
126             | SCALER_PIX_EXPAND
127             | SCALER_BURST_PER_PLANE;
128
129   switch(besr.fourcc)
130     {
131     case IMGFMT_RGB15:
132     case IMGFMT_BGR15: bes_flags |= SCALER_SOURCE_15BPP; break;
133     case IMGFMT_RGB16:
134     case IMGFMT_BGR16: bes_flags |= SCALER_SOURCE_16BPP; break;
135     case IMGFMT_RGB32:
136     case IMGFMT_BGR32: bes_flags |= SCALER_SOURCE_32BPP; break;
137     /* 4:1:0 */
138     case IMGFMT_IF09:
139     case IMGFMT_YVU9:  bes_flags |= SCALER_SOURCE_YUV9; break;
140     /* 4:0:0 */
141     case IMGFMT_Y800:
142     case IMGFMT_Y8:
143     /* 4:2:0 */
144     case IMGFMT_IYUV:
145     case IMGFMT_I420:
146     case IMGFMT_YV12:  bes_flags |= SCALER_SOURCE_YUV12; break;
147     /* 4:2:2 */
148     case IMGFMT_YVYU:
149     case IMGFMT_UYVY:  bes_flags |= SCALER_SOURCE_YVYU422; break;
150     case IMGFMT_YUY2:
151     default:           bes_flags |= SCALER_SOURCE_VYUY422; break;
152     }
153
154   aty128_wait_for_fifo(2);
155   aty_st_le32(OV0_SCALE_CNTL, bes_flags);
156   aty_st_le32(OV0_REG_LOAD_CNTL, 0);
157 }
158
159 static void
160 ati128_stop_video(void)
161 {
162   aty128_wait_for_idle();
163   aty_st_le32(OV0_SCALE_CNTL, SCALER_SOFT_RESET);
164   aty_st_le32(OV0_EXCLUSIVE_HORZ, 0);
165   aty_st_le32(OV0_AUTO_FLIP_CNTL, 0);
166   aty_st_le32(OV0_FILTER_CNTL, FILTER_HARDCODED_COEF);
167   aty_st_le32(OV0_KEY_CNTL, GRAPHIC_KEY_FN_NE);
168   aty_st_le32(OV0_TEST, 0);
169 }
170
171 /* return "alignment of Y,U,V component" */
172 static unsigned
173 ati128_query_pitch(unsigned fourcc, const vidix_yuv_t *spitch)
174 {
175   unsigned pitch,spy,spv,spu;
176   spy = spv = spu = 0;
177   switch (spitch->y)
178     {
179     case 16:
180     case 32:
181     case 64:
182     case 128:
183     case 256: spy = spitch->y; break;
184     default: break;
185     }
186   switch(spitch->u)
187     {
188     case 16:
189     case 32:
190     case 64:
191     case 128:
192     case 256: spu = spitch->u; break;
193     default: break;
194     }
195   switch(spitch->v)
196     {
197     case 16:
198     case 32:
199     case 64:
200     case 128:
201     case 256: spv = spitch->v; break;
202     default: break;
203     }
204   switch(fourcc)
205     {
206     /* 4:2:0 */
207     case IMGFMT_IYUV:
208     case IMGFMT_YV12:
209     case IMGFMT_I420:
210       if (spy > 16 && spu == spy/2 && spv == spy/2)     pitch = spy;
211       else                                              pitch = 32/*16*/;
212       break;
213     case IMGFMT_YVU9:
214       if (spy > 32 && spu == spy/4 && spv == spy/4)     pitch = spy;
215       else                                              pitch = 64;
216       break;
217     default:
218       if (spy >= 16)                                    pitch = spy;
219       else                                              pitch = 16;
220       break;
221     }
222   return pitch;
223 }
224
225 static int
226 ati128_init_video(vidix_playback_t *config)
227 {
228   l4_uint32_t i,tmp,src_w,src_h,dest_w,dest_h,pitch;
229   l4_uint32_t h_inc,step_by,left,leftUV,top;
230   int is_400,is_410,is_420,is_rgb32,is_rgb,best_pitch,mpitch;
231   unsigned int ecp_div;
232
233   aty128_wait_for_fifo(3);
234
235   aty_st_le32(OV0_GRAPHICS_KEY_MSK, besr.graphics_key_msk);
236   aty_st_le32(OV0_GRAPHICS_KEY_CLR, besr.graphics_key_clr);
237   if (besr.ckey_on)
238     aty_st_le32(OV0_KEY_CNTL,
239                 VIDEO_KEY_FN_TRUE|GRAPHIC_KEY_FN_EQ|CMP_MIX_AND);
240   else
241     aty_st_le32(OV0_KEY_CNTL,
242                 VIDEO_KEY_FN_TRUE|GRAPHIC_KEY_FN_TRUE|CMP_MIX_AND);
243
244   ati128_stop_video();
245   
246   left   = config->src.x << 16;
247   top    = config->src.y << 16;
248   src_h  = config->src.h;
249   src_w  = config->src.w;
250   is_400 = is_410 = is_420 = is_rgb32 = is_rgb = 0;
251   if (config->fourcc == IMGFMT_YV12 ||
252       config->fourcc == IMGFMT_I420 ||
253       config->fourcc == IMGFMT_IYUV) 
254     is_420 = 1;
255   if (config->fourcc == IMGFMT_YVU9 ||
256       config->fourcc == IMGFMT_IF09)
257     is_410 = 1;
258   if (config->fourcc == IMGFMT_Y800 ||
259       config->fourcc == IMGFMT_Y8) 
260     is_400 = 1;
261   if (config->fourcc == IMGFMT_RGB32 ||
262       config->fourcc == IMGFMT_BGR32)
263     is_rgb32 = 1;
264   if (config->fourcc == IMGFMT_RGB32 ||
265       config->fourcc == IMGFMT_BGR32 ||
266       config->fourcc == IMGFMT_RGB24 ||
267       config->fourcc == IMGFMT_BGR24 ||
268       config->fourcc == IMGFMT_RGB16 ||
269       config->fourcc == IMGFMT_BGR16 ||
270       config->fourcc == IMGFMT_RGB15 ||
271       config->fourcc == IMGFMT_BGR15)
272     is_rgb = 1;
273
274   best_pitch = ati128_query_pitch(config->fourcc,&config->src.pitch);
275   mpitch = best_pitch-1;
276   switch(config->fourcc)
277     {
278       /* 4:0:0 */
279     case IMGFMT_Y800:
280     case IMGFMT_Y8:
281       /* 4:1:0 */
282     case IMGFMT_YVU9:
283     case IMGFMT_IF09:
284       /* 4:2:0 */
285     case IMGFMT_IYUV:
286     case IMGFMT_YV12:
287     case IMGFMT_I420: pitch = (src_w + mpitch) & ~mpitch;
288                       config->dest.pitch.y = 
289                       config->dest.pitch.u = 
290                       config->dest.pitch.v = best_pitch;
291                       break;
292     /* RGB 4:4:4:4 */
293     case IMGFMT_RGB32:
294     case IMGFMT_BGR32: pitch = (src_w*4 + mpitch) & ~mpitch;
295                        config->dest.pitch.y = 
296                        config->dest.pitch.u = 
297                        config->dest.pitch.v = best_pitch;
298                        break;
299     /* 4:2:2 */
300     default: /* RGB15, RGB16, YVYU, UYVY, YUY2 */
301                        pitch = ((src_w*2) + mpitch) & ~mpitch;
302                        config->dest.pitch.y =
303                        config->dest.pitch.u =
304                        config->dest.pitch.v = best_pitch;
305                        break;
306     }
307   dest_w = config->dest.w;
308   dest_h = config->dest.h;
309   besr.fourcc = config->fourcc;
310   besr.v_inc = (src_h << 20) / dest_h;
311   h_inc = (src_w << 12) / dest_w;
312
313   ecp_div = (aty_in_pll(VCLK_ECP_CNTL) >> 8) & 3;
314   h_inc <<= ecp_div;
315
316   step_by = 1;
317   while (h_inc >= (2 << 12)) 
318     {
319       step_by++;
320       h_inc >>= 1;
321     }
322
323   /* keep everything in 16.16 */
324   besr.base_addr = aty_ld_le32(DISPLAY_BASE_ADDR);
325   config->offsets[0] = 0;
326   for (i=1; i<besr.vid_nbufs; i++)
327     config->offsets[i] = config->offsets[i-1]+config->frame_size;
328
329   if (is_420 || is_410 || is_400)
330     {
331       l4_uint32_t d1line,d2line,d3line;
332
333       d1line = top*pitch;
334       if (is_420)
335         {
336           d2line = src_h*pitch+(d1line>>2);
337           d3line = d2line+((src_h*pitch)>>2);
338         }
339       else if (is_410)
340         {
341           d2line = src_h*pitch+(d1line>>4);
342           d3line = d2line+((src_h*pitch)>>4);
343         }
344       else
345         {
346           d2line = 0;
347           d3line = 0;
348         }
349       d1line += (left >> 16) & ~15;
350       if (is_420)
351         {
352           d2line += (left >> 17) & ~15;
353           d3line += (left >> 17) & ~15;
354         }
355       else if(is_410)
356         {
357           d2line += (left >> 18) & ~15;
358           d3line += (left >> 18) & ~15;
359         }
360
361       config->offset.y = d1line & VIF_BUF0_BASE_ADRS_MASK;
362       if (is_400)
363         {
364           config->offset.v = 0;
365           config->offset.u = 0;
366         }
367       else
368         {
369           config->offset.v = d2line & VIF_BUF1_BASE_ADRS_MASK;
370           config->offset.u = d3line & VIF_BUF2_BASE_ADRS_MASK;
371         }
372
373       for (i=0; i<besr.vid_nbufs; i++)
374         {
375           besr.vid_buf_base_adrs_y[i] = 
376             ((ati128_overlay_off + config->offsets[i]
377               + config->offset.y) & VIF_BUF0_BASE_ADRS_MASK);
378           if (is_400)
379             {
380               besr.vid_buf_base_adrs_v[i]=0;
381               besr.vid_buf_base_adrs_u[i]=0;
382             }
383           else
384             {
385               if (besr.fourcc == IMGFMT_I420 || besr.fourcc == IMGFMT_IYUV)
386                 {
387                   besr.vid_buf_base_adrs_u[i] = 
388                     ((ati128_overlay_off + config->offsets[i] 
389                       + config->offset.v) & VIF_BUF1_BASE_ADRS_MASK)
390                     | VIF_BUF1_PITCH_SEL;
391                   besr.vid_buf_base_adrs_v[i] = 
392                     ((ati128_overlay_off + config->offsets[i]
393                       + config->offset.u) & VIF_BUF2_BASE_ADRS_MASK)
394                     | VIF_BUF2_PITCH_SEL;
395                 }
396               else
397                 {
398                   besr.vid_buf_base_adrs_v[i] = 
399                     ((ati128_overlay_off + config->offsets[i]
400                       + config->offset.v) & VIF_BUF1_BASE_ADRS_MASK)
401                     | VIF_BUF1_PITCH_SEL;
402                   besr.vid_buf_base_adrs_u[i] =
403                     ((ati128_overlay_off + config->offsets[i]
404                       + config->offset.u) & VIF_BUF2_BASE_ADRS_MASK)
405                     | VIF_BUF2_PITCH_SEL;
406                 }
407             }
408         }
409       config->offset.y = (besr.vid_buf_base_adrs_y[0] 
410                           & VIF_BUF0_BASE_ADRS_MASK) - ati128_overlay_off;
411       if (is_400)
412         {
413           config->offset.v = 0;
414           config->offset.u = 0;
415         }
416       else
417         {
418           config->offset.v = (besr.vid_buf_base_adrs_v[0]
419                               & VIF_BUF1_BASE_ADRS_MASK) - ati128_overlay_off;
420           config->offset.u = (besr.vid_buf_base_adrs_u[0]
421                               & VIF_BUF2_BASE_ADRS_MASK) - ati128_overlay_off;
422         }
423     }
424   else
425     {
426       config->offset.y =
427       config->offset.u =
428       config->offset.v = ((left & ~7) << 1) & VIF_BUF0_BASE_ADRS_MASK;
429       for (i=0; i<besr.vid_nbufs; i++)
430         {
431           besr.vid_buf_base_adrs_y[i] =
432           besr.vid_buf_base_adrs_u[i] =
433           besr.vid_buf_base_adrs_v[i] = ati128_overlay_off 
434                                       + config->offsets[i] + config->offset.y;
435         }
436     }
437
438   tmp = (left & 0x0003ffff) + 0x00028000 + (h_inc << 3);
439   besr.p1_h_accum_init = ((tmp <<  4) & 0x000f8000) 
440                        | ((tmp << 12) & 0xf0000000);
441
442   tmp = ((left >> 1) & 0x0001ffff) + 0x00028000 + (h_inc << 2);
443   besr.p23_h_accum_init = ((tmp <<  4) & 0x000f8000) 
444                         | ((tmp << 12) & 0x70000000);
445   tmp = (top & 0x0000ffff) + 0x00018000;
446   besr.p1_v_accum_init = ((tmp << 4) & OV0_P1_V_ACCUM_INIT_MASK)
447                        | (OV0_P1_MAX_LN_IN_PER_LN_OUT & 1);
448
449   tmp = ((top >> 1) & 0x0000ffff) + 0x00018000;
450   besr.p23_v_accum_init =  (is_420||is_410) 
451                               ? ((tmp << 4) & OV0_P23_V_ACCUM_INIT_MASK) 
452                                 |(OV0_P23_MAX_LN_IN_PER_LN_OUT & 1) 
453                               : 0;
454
455   leftUV = (left >> (is_410?18:17)) & 15;
456   left   = (left >> 16) & 15;
457   if (is_rgb && !is_rgb32)
458     h_inc<<=1;
459   if (is_rgb32)
460     besr.h_inc = (h_inc >> 1) | ((h_inc >> 1) << 16);
461   else if (is_410)
462     besr.h_inc = h_inc | ((h_inc >> 2) << 16);
463   else
464     besr.h_inc = h_inc | ((h_inc >> 1) << 16);
465   besr.step_by = step_by | (step_by << 8);
466   besr.y_x_start = config->dest.x 
467                  | (config->dest.y << 16);
468   besr.y_x_end   = (config->dest.x + dest_w) 
469                  | ((config->dest.y + dest_h) << 16);
470   besr.p1_blank_lines_at_top = P1_BLNK_LN_AT_TOP_M1_MASK|((src_h-1)<<16);
471   if (is_420 || is_410)
472     {
473       src_h = (src_h + 1) >> (is_410?2:1);
474       besr.p23_blank_lines_at_top = P23_BLNK_LN_AT_TOP_M1_MASK|((src_h-1)<<16);
475     }
476   else
477     besr.p23_blank_lines_at_top = 0;
478
479   besr.vid_buf_pitch0_value = pitch;
480   besr.vid_buf_pitch1_value = is_410 ? pitch>>2 : is_420 ? pitch>>1 : pitch;
481   besr.p1_x_start_end = (src_w+left-1)|(left<<16);
482   if (is_410||is_420)
483     src_w>>=is_410 ? 2 : 1;
484   if (is_400)
485     {
486       besr.p2_x_start_end = 0;
487       besr.p3_x_start_end = 0;
488     }
489   else
490     {
491       besr.p2_x_start_end = (src_w+left-1)|(leftUV<<16);
492       besr.p3_x_start_end = besr.p2_x_start_end;
493     }
494
495   return 0;
496 }
497
498 static void
499 ati128_compute_framesize(vidix_playback_t *info)
500 {
501   unsigned pitch,awidth;
502
503   pitch = ati128_query_pitch(info->fourcc, &info->src.pitch);
504   switch(info->fourcc)
505     {
506     case IMGFMT_I420:
507     case IMGFMT_YV12:
508     case IMGFMT_IYUV:
509       awidth = (info->src.w + (pitch-1)) & ~(pitch-1);
510       info->frame_size = awidth*(info->src.h+info->src.h/2);
511       break;
512     case IMGFMT_YVU9:
513       awidth = (info->src.w + (pitch-1)) & ~(pitch-1);
514       info->frame_size = awidth*(info->src.h+info->src.h/8);
515       break;
516     case IMGFMT_BGR32:
517       awidth = (info->src.w*4 + (pitch-1)) & ~(pitch-1);
518       info->frame_size = (awidth*info->src.h);
519       break;
520       /* YUY2 YVYU, RGB15, RGB16 */
521     default:    
522       awidth = (info->src.w*2 + (pitch-1)) & ~(pitch-1);
523       info->frame_size = (awidth*info->src.h);
524       break;
525     }
526
527   info->frame_size = (info->frame_size + 1024*1024 - 1) & ~(1024*1024-1);
528 }
529
530   static int
531 ati128_video_playback(vidix_playback_t *info)
532 {
533   ati128_compute_framesize(info);
534
535   if (info->num_frames>4)
536     info->num_frames=4;
537
538   for (; info->num_frames>0; info->num_frames--)
539     {
540       /* align offset so we can map it as flexpage */
541       ati128_overlay_off =
542         (hw_vid_mem_size - info->frame_size*info->num_frames) & 0xfff00000;
543       if (ati128_overlay_off>0)
544         break;
545     }
546   if (info->num_frames <= 0) 
547     return -L4_EINVAL;
548
549   besr.vid_nbufs = info->num_frames;
550   info->dga_addr = (char *)hw_map_vid_mem_addr + ati128_overlay_off;
551   ati128_init_video(info);
552   return 0;
553 }
554
555   static void
556 ati128_set_grkey(const vidix_grkey_t *grkey)
557 {
558   if(grkey->ckey.op == CKEY_TRUE)
559     {
560       besr.ckey_on = 1;
561       switch (hw_bits)
562         {
563         case 15:
564           besr.graphics_key_msk=0x7FFF;
565           besr.graphics_key_clr=
566             ((grkey->ckey.blue &0xF8)>>3)
567             | ((grkey->ckey.green&0xF8)<<2)
568             | ((grkey->ckey.red  &0xF8)<<7);
569           break;
570         case 16:
571           besr.graphics_key_msk=0xFFFF;
572           besr.graphics_key_clr=
573             ((grkey->ckey.blue &0xF8)>>3)
574             | ((grkey->ckey.green&0xFC)<<3)
575             | ((grkey->ckey.red  &0xF8)<<8);
576           break;
577         case 24:
578           besr.graphics_key_msk=0xFFFFFF;
579           besr.graphics_key_clr=
580             ((grkey->ckey.blue &0xFF))
581             | ((grkey->ckey.green&0xFF)<<8)
582             | ((grkey->ckey.red  &0xFF)<<16);
583           break;
584         case 32:
585           besr.graphics_key_msk=0xFFFFFF;
586           besr.graphics_key_clr=
587             ((grkey->ckey.blue &0xFF))
588             | ((grkey->ckey.green&0xFF)<<8)
589             | ((grkey->ckey.red  &0xFF)<<16);
590           break;
591         default:
592           besr.ckey_on=0;
593           besr.graphics_key_msk=0;
594           besr.graphics_key_clr=0;
595         }
596     }
597   else
598     {
599       besr.ckey_on=0;
600       besr.graphics_key_msk=0;
601       besr.graphics_key_clr=0;
602     }
603
604   aty128_wait_for_fifo(3);
605   aty_st_le32(OV0_GRAPHICS_KEY_MSK, besr.graphics_key_msk);
606   aty_st_le32(OV0_GRAPHICS_KEY_CLR, besr.graphics_key_clr);
607   if (besr.ckey_on)
608     aty_st_le32(OV0_KEY_CNTL,
609         VIDEO_KEY_FN_TRUE|GRAPHIC_KEY_FN_EQ|CMP_MIX_AND);
610   else
611     aty_st_le32(OV0_KEY_CNTL,
612         VIDEO_KEY_FN_TRUE|GRAPHIC_KEY_FN_TRUE|CMP_MIX_AND);
613 }
614
615   static void
616 ati128_set_equalizer(const vidix_video_eq_t *eq)
617 {
618   unsigned color_ctrl = aty_ld_le32(OV0_COLOUR_CNTL);
619
620   if (eq->cap & VEQ_CAP_BRIGHTNESS)
621     {
622       int br = eq->brightness * 64 / 1000;
623       if (br < -64)
624         br = -64;
625       if (br > 63)
626         br = 63;
627       color_ctrl = (color_ctrl & 0xffffff00) | (br & 0x7f);
628     }
629   if (eq->cap & VEQ_CAP_SATURATION)
630     {
631       int sat = (eq->saturation + 1000) *16 / 1000;
632       if (sat < 0)
633         sat = 0;
634       if (sat > 31)
635         sat = 31;
636       color_ctrl = (color_ctrl & 0xff0000ff) | (sat << 8) | (sat << 16);
637     }
638
639   aty_st_le32(OV0_COLOUR_CNTL, color_ctrl);
640 }
641
642   void
643 ati128_vid_init(con_accel_t *accel)
644 {
645   accel->cscs_init  = ati128_video_playback;
646   accel->cscs_start = ati128_start_video;
647   accel->cscs_stop  = ati128_stop_video;
648   accel->cscs_grkey = ati128_set_grkey;
649   accel->caps      |= ACCEL_FAST_CSCS_YV12 | ACCEL_COLOR_KEY;
650   accel->cscs_eq    = ati128_set_equalizer;
651   accel->caps      |= ACCEL_EQ_BRIGHTNESS | ACCEL_EQ_SATURATION;
652 }
653