3 * \brief Hardware Acceleration for ATI Rage128 cards (backend scaler)
6 * \author Frank Mehnert <fm3@os.inf.tu-dresden.de> */
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.
14 /* most stuff taken from MPlayer/vidix driver */
18 #include <l4/sys/types.h>
19 #include <l4/sys/err.h>
20 #include <l4/sys/consts.h>
30 /* base address of yuv framebuffer */
33 /* YUV BES registers */
34 l4_uint32_t reg_load_cntl;
37 l4_uint32_t y_x_start;
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;
62 /* Configurable stuff */
67 l4_uint32_t graphics_key_clr;
68 l4_uint32_t graphics_key_msk;
69 l4_uint32_t ckey_cntl;
73 static bes_registers_t besr;
74 static l4_int32_t ati128_overlay_off;
78 ati128_start_video(void)
80 l4_uint32_t bes_flags;
82 aty128_wait_for_fifo(1);
83 aty_st_le32(OV0_REG_LOAD_CNTL, REG_LD_CTL_LOCK);
85 aty128_wait_for_idle();
86 while (!(aty_ld_le32(OV0_REG_LOAD_CNTL) & REG_LD_CTL_LOCK_READBACK))
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);
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);
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);
123 bes_flags = SCALER_ENABLE
124 | SCALER_SMART_SWITCH
127 | SCALER_BURST_PER_PLANE;
132 case IMGFMT_BGR15: bes_flags |= SCALER_SOURCE_15BPP; break;
134 case IMGFMT_BGR16: bes_flags |= SCALER_SOURCE_16BPP; break;
136 case IMGFMT_BGR32: bes_flags |= SCALER_SOURCE_32BPP; break;
139 case IMGFMT_YVU9: bes_flags |= SCALER_SOURCE_YUV9; break;
146 case IMGFMT_YV12: bes_flags |= SCALER_SOURCE_YUV12; break;
149 case IMGFMT_UYVY: bes_flags |= SCALER_SOURCE_YVYU422; break;
151 default: bes_flags |= SCALER_SOURCE_VYUY422; break;
154 aty128_wait_for_fifo(2);
155 aty_st_le32(OV0_SCALE_CNTL, bes_flags);
156 aty_st_le32(OV0_REG_LOAD_CNTL, 0);
160 ati128_stop_video(void)
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);
171 /* return "alignment of Y,U,V component" */
173 ati128_query_pitch(unsigned fourcc, const vidix_yuv_t *spitch)
175 unsigned pitch,spy,spv,spu;
183 case 256: spy = spitch->y; break;
192 case 256: spu = spitch->u; break;
201 case 256: spv = spitch->v; break;
210 if (spy > 16 && spu == spy/2 && spv == spy/2) pitch = spy;
211 else pitch = 32/*16*/;
214 if (spy > 32 && spu == spy/4 && spv == spy/4) pitch = spy;
218 if (spy >= 16) pitch = spy;
226 ati128_init_video(vidix_playback_t *config)
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;
233 aty128_wait_for_fifo(3);
235 aty_st_le32(OV0_GRAPHICS_KEY_MSK, besr.graphics_key_msk);
236 aty_st_le32(OV0_GRAPHICS_KEY_CLR, besr.graphics_key_clr);
238 aty_st_le32(OV0_KEY_CNTL,
239 VIDEO_KEY_FN_TRUE|GRAPHIC_KEY_FN_EQ|CMP_MIX_AND);
241 aty_st_le32(OV0_KEY_CNTL,
242 VIDEO_KEY_FN_TRUE|GRAPHIC_KEY_FN_TRUE|CMP_MIX_AND);
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)
255 if (config->fourcc == IMGFMT_YVU9 ||
256 config->fourcc == IMGFMT_IF09)
258 if (config->fourcc == IMGFMT_Y800 ||
259 config->fourcc == IMGFMT_Y8)
261 if (config->fourcc == IMGFMT_RGB32 ||
262 config->fourcc == IMGFMT_BGR32)
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)
274 best_pitch = ati128_query_pitch(config->fourcc,&config->src.pitch);
275 mpitch = best_pitch-1;
276 switch(config->fourcc)
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;
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;
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;
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;
313 ecp_div = (aty_in_pll(VCLK_ECP_CNTL) >> 8) & 3;
317 while (h_inc >= (2 << 12))
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;
329 if (is_420 || is_410 || is_400)
331 l4_uint32_t d1line,d2line,d3line;
336 d2line = src_h*pitch+(d1line>>2);
337 d3line = d2line+((src_h*pitch)>>2);
341 d2line = src_h*pitch+(d1line>>4);
342 d3line = d2line+((src_h*pitch)>>4);
349 d1line += (left >> 16) & ~15;
352 d2line += (left >> 17) & ~15;
353 d3line += (left >> 17) & ~15;
357 d2line += (left >> 18) & ~15;
358 d3line += (left >> 18) & ~15;
361 config->offset.y = d1line & VIF_BUF0_BASE_ADRS_MASK;
364 config->offset.v = 0;
365 config->offset.u = 0;
369 config->offset.v = d2line & VIF_BUF1_BASE_ADRS_MASK;
370 config->offset.u = d3line & VIF_BUF2_BASE_ADRS_MASK;
373 for (i=0; i<besr.vid_nbufs; i++)
375 besr.vid_buf_base_adrs_y[i] =
376 ((ati128_overlay_off + config->offsets[i]
377 + config->offset.y) & VIF_BUF0_BASE_ADRS_MASK);
380 besr.vid_buf_base_adrs_v[i]=0;
381 besr.vid_buf_base_adrs_u[i]=0;
385 if (besr.fourcc == IMGFMT_I420 || besr.fourcc == IMGFMT_IYUV)
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;
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;
409 config->offset.y = (besr.vid_buf_base_adrs_y[0]
410 & VIF_BUF0_BASE_ADRS_MASK) - ati128_overlay_off;
413 config->offset.v = 0;
414 config->offset.u = 0;
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;
428 config->offset.v = ((left & ~7) << 1) & VIF_BUF0_BASE_ADRS_MASK;
429 for (i=0; i<besr.vid_nbufs; i++)
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;
438 tmp = (left & 0x0003ffff) + 0x00028000 + (h_inc << 3);
439 besr.p1_h_accum_init = ((tmp << 4) & 0x000f8000)
440 | ((tmp << 12) & 0xf0000000);
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);
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)
455 leftUV = (left >> (is_410?18:17)) & 15;
456 left = (left >> 16) & 15;
457 if (is_rgb && !is_rgb32)
460 besr.h_inc = (h_inc >> 1) | ((h_inc >> 1) << 16);
462 besr.h_inc = h_inc | ((h_inc >> 2) << 16);
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)
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);
477 besr.p23_blank_lines_at_top = 0;
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);
483 src_w>>=is_410 ? 2 : 1;
486 besr.p2_x_start_end = 0;
487 besr.p3_x_start_end = 0;
491 besr.p2_x_start_end = (src_w+left-1)|(leftUV<<16);
492 besr.p3_x_start_end = besr.p2_x_start_end;
499 ati128_compute_framesize(vidix_playback_t *info)
501 unsigned pitch,awidth;
503 pitch = ati128_query_pitch(info->fourcc, &info->src.pitch);
509 awidth = (info->src.w + (pitch-1)) & ~(pitch-1);
510 info->frame_size = awidth*(info->src.h+info->src.h/2);
513 awidth = (info->src.w + (pitch-1)) & ~(pitch-1);
514 info->frame_size = awidth*(info->src.h+info->src.h/8);
517 awidth = (info->src.w*4 + (pitch-1)) & ~(pitch-1);
518 info->frame_size = (awidth*info->src.h);
520 /* YUY2 YVYU, RGB15, RGB16 */
522 awidth = (info->src.w*2 + (pitch-1)) & ~(pitch-1);
523 info->frame_size = (awidth*info->src.h);
527 info->frame_size = (info->frame_size + 1024*1024 - 1) & ~(1024*1024-1);
531 ati128_video_playback(vidix_playback_t *info)
533 ati128_compute_framesize(info);
535 if (info->num_frames>4)
538 for (; info->num_frames>0; info->num_frames--)
540 /* align offset so we can map it as flexpage */
542 (hw_vid_mem_size - info->frame_size*info->num_frames) & 0xfff00000;
543 if (ati128_overlay_off>0)
546 if (info->num_frames <= 0)
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);
556 ati128_set_grkey(const vidix_grkey_t *grkey)
558 if(grkey->ckey.op == CKEY_TRUE)
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);
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);
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);
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);
593 besr.graphics_key_msk=0;
594 besr.graphics_key_clr=0;
600 besr.graphics_key_msk=0;
601 besr.graphics_key_clr=0;
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);
608 aty_st_le32(OV0_KEY_CNTL,
609 VIDEO_KEY_FN_TRUE|GRAPHIC_KEY_FN_EQ|CMP_MIX_AND);
611 aty_st_le32(OV0_KEY_CNTL,
612 VIDEO_KEY_FN_TRUE|GRAPHIC_KEY_FN_TRUE|CMP_MIX_AND);
616 ati128_set_equalizer(const vidix_video_eq_t *eq)
618 unsigned color_ctrl = aty_ld_le32(OV0_COLOUR_CNTL);
620 if (eq->cap & VEQ_CAP_BRIGHTNESS)
622 int br = eq->brightness * 64 / 1000;
627 color_ctrl = (color_ctrl & 0xffffff00) | (br & 0x7f);
629 if (eq->cap & VEQ_CAP_SATURATION)
631 int sat = (eq->saturation + 1000) *16 / 1000;
636 color_ctrl = (color_ctrl & 0xff0000ff) | (sat << 8) | (sat << 16);
639 aty_st_le32(OV0_COLOUR_CNTL, color_ctrl);
643 ati128_vid_init(con_accel_t *accel)
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;