1 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
3 #include <linux/kernel.h>
4 #include <linux/export.h>
5 #include <media/saa7146_vv.h>
7 static void calculate_output_format_register(struct saa7146_dev
* saa
, u32 palette
, u32
* clip_format
)
9 /* clear out the necessary bits */
10 *clip_format
&= 0x0000ffff;
11 /* set these bits new */
12 *clip_format
|= (( ((palette
&0xf00)>>8) << 30) | ((palette
&0x00f) << 24) | (((palette
&0x0f0)>>4) << 16));
15 static void calculate_hps_source_and_sync(struct saa7146_dev
*dev
, int source
, int sync
, u32
* hps_ctrl
)
17 *hps_ctrl
&= ~(MASK_30
| MASK_31
| MASK_28
);
18 *hps_ctrl
|= (source
<< 30) | (sync
<< 28);
21 static void calculate_hxo_and_hyo(struct saa7146_vv
*vv
, u32
* hps_h_scale
, u32
* hps_ctrl
)
25 hyo
= vv
->standard
->v_offset
;
26 hxo
= vv
->standard
->h_offset
;
28 *hps_h_scale
&= ~(MASK_B0
| 0xf00);
29 *hps_h_scale
|= (hxo
<< 0);
31 *hps_ctrl
&= ~(MASK_W0
| MASK_B2
);
32 *hps_ctrl
|= (hyo
<< 12);
35 /* helper functions for the calculation of the horizontal- and vertical
36 scaling registers, clip-format-register etc ...
37 these functions take pointers to the (most-likely read-out
38 original-values) and manipulate them according to the requested
42 /* hps_coeff used for CXY and CXUV; scale 1/1 -> scale 1/64 */
46 } hps_h_coeff_tab
[] = {
47 {0x00, 2}, {0x02, 4}, {0x00, 4}, {0x06, 8}, {0x02, 8},
48 {0x08, 8}, {0x00, 8}, {0x1E, 16}, {0x0E, 8}, {0x26, 8},
49 {0x06, 8}, {0x42, 8}, {0x02, 8}, {0x80, 8}, {0x00, 8},
50 {0xFE, 16}, {0xFE, 8}, {0x7E, 8}, {0x7E, 8}, {0x3E, 8},
51 {0x3E, 8}, {0x1E, 8}, {0x1E, 8}, {0x0E, 8}, {0x0E, 8},
52 {0x06, 8}, {0x06, 8}, {0x02, 8}, {0x02, 8}, {0x00, 8},
53 {0x00, 8}, {0xFE, 16}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8},
54 {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8},
55 {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8},
56 {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0x7E, 8},
57 {0x7E, 8}, {0x3E, 8}, {0x3E, 8}, {0x1E, 8}, {0x1E, 8},
58 {0x0E, 8}, {0x0E, 8}, {0x06, 8}, {0x06, 8}, {0x02, 8},
59 {0x02, 8}, {0x00, 8}, {0x00, 8}, {0xFE, 16}
62 /* table of attenuation values for horizontal scaling */
63 static u8 h_attenuation
[] = { 1, 2, 4, 8, 2, 4, 8, 16, 0};
65 /* calculate horizontal scale registers */
66 static int calculate_h_scale_registers(struct saa7146_dev
*dev
,
67 int in_x
, int out_x
, int flip_lr
,
68 u32
* hps_ctrl
, u32
* hps_v_gain
, u32
* hps_h_prescale
, u32
* hps_h_scale
)
70 /* horizontal prescaler */
71 u32 dcgx
= 0, xpsc
= 0, xacm
= 0, cxy
= 0, cxuv
= 0;
72 /* horizontal scaler */
73 u32 xim
= 0, xp
= 0, xsci
=0;
74 /* vertical scale & gain */
77 /* helper variables */
78 u32 h_atten
= 0, i
= 0;
84 /* mask out vanity-bit */
85 *hps_ctrl
&= ~MASK_29
;
87 /* calculate prescale-(xspc)-value: [n .. 1/2) : 1
99 /* if flip_lr-bit is set, number of pixels after
100 horizontal prescaling must be < 384 */
101 if ( 0 != flip_lr
) {
104 *hps_ctrl
|= MASK_29
;
106 while (in_x
/ xpsc
>= 384 )
109 /* if zooming is wanted, number of pixels after
110 horizontal prescaling must be < 768 */
112 while ( in_x
/ xpsc
>= 768 )
116 /* maximum prescale is 64 (p.69) */
123 /* set horizontal filter parameters (CXY = CXUV) */
124 cxy
= hps_h_coeff_tab
[( (xpsc
- 1) < 63 ? (xpsc
- 1) : 63 )].hps_coeff
;
127 /* calculate and set horizontal fine scale (xsci) */
129 /* bypass the horizontal scaler ? */
130 if ( (in_x
== out_x
) && ( 1 == xpsc
) )
133 xsci
= ( (1024 * in_x
) / (out_x
* xpsc
) ) + xpsc
;
135 /* set start phase for horizontal fine scale (xp) to 0 */
138 /* set xim, if we bypass the horizontal scaler */
144 /* if the prescaler is bypassed, enable horizontal
145 accumulation mode (xacm) and clear dcgx */
151 /* get best match in the table of attenuations
152 for horizontal scaling */
153 h_atten
= hps_h_coeff_tab
[( (xpsc
- 1) < 63 ? (xpsc
- 1) : 63 )].weight_sum
;
155 for (i
= 0; h_attenuation
[i
] != 0; i
++) {
156 if (h_attenuation
[i
] >= h_atten
)
163 /* the horizontal scaling increment controls the UV filter
164 to reduce the bandwidth to improve the display quality,
168 else if ( xsci
< 0x600)
170 else if ( xsci
< 0x680)
172 else if ( xsci
< 0x700)
178 *hps_v_gain
&= MASK_W0
|MASK_B2
;
179 *hps_v_gain
|= (pfuv
<< 24);
181 *hps_h_scale
&= ~(MASK_W1
| 0xf000);
182 *hps_h_scale
|= (xim
<< 31) | (xp
<< 24) | (xsci
<< 12);
184 *hps_h_prescale
|= (dcgx
<< 27) | ((xpsc
-1) << 18) | (xacm
<< 17) | (cxy
<< 8) | (cxuv
<< 0);
192 } hps_v_coeff_tab
[] = {
193 {0x0100, 2}, {0x0102, 4}, {0x0300, 4}, {0x0106, 8}, {0x0502, 8},
194 {0x0708, 8}, {0x0F00, 8}, {0x011E, 16}, {0x110E, 16}, {0x1926, 16},
195 {0x3906, 16}, {0x3D42, 16}, {0x7D02, 16}, {0x7F80, 16}, {0xFF00, 16},
196 {0x01FE, 32}, {0x01FE, 32}, {0x817E, 32}, {0x817E, 32}, {0xC13E, 32},
197 {0xC13E, 32}, {0xE11E, 32}, {0xE11E, 32}, {0xF10E, 32}, {0xF10E, 32},
198 {0xF906, 32}, {0xF906, 32}, {0xFD02, 32}, {0xFD02, 32}, {0xFF00, 32},
199 {0xFF00, 32}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64},
200 {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64},
201 {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64},
202 {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x817E, 64},
203 {0x817E, 64}, {0xC13E, 64}, {0xC13E, 64}, {0xE11E, 64}, {0xE11E, 64},
204 {0xF10E, 64}, {0xF10E, 64}, {0xF906, 64}, {0xF906, 64}, {0xFD02, 64},
205 {0xFD02, 64}, {0xFF00, 64}, {0xFF00, 64}, {0x01FE, 128}
208 /* table of attenuation values for vertical scaling */
209 static u16 v_attenuation
[] = { 2, 4, 8, 16, 32, 64, 128, 256, 0};
211 /* calculate vertical scale registers */
212 static int calculate_v_scale_registers(struct saa7146_dev
*dev
, enum v4l2_field field
,
213 int in_y
, int out_y
, u32
* hps_v_scale
, u32
* hps_v_gain
)
217 /* vertical scaling */
218 u32 yacm
= 0, ysci
= 0, yacl
= 0, ypo
= 0, ype
= 0;
219 /* vertical scale & gain */
220 u32 dcgy
= 0, cya_cyb
= 0;
222 /* helper variables */
223 u32 v_atten
= 0, i
= 0;
225 /* error, if vertical zooming */
226 if ( in_y
< out_y
) {
230 /* linear phase interpolation may be used
231 if scaling is between 1 and 1/2 (both fields used)
232 or scaling is between 1/2 and 1/4 (if only one field is used) */
234 if (V4L2_FIELD_HAS_BOTH(field
)) {
235 if( 2*out_y
>= in_y
) {
238 } else if (field
== V4L2_FIELD_TOP
239 || field
== V4L2_FIELD_ALTERNATE
240 || field
== V4L2_FIELD_BOTTOM
) {
241 if( 4*out_y
>= in_y
) {
252 /* calculate scaling increment */
254 ysci
= ((1024 * in_y
) / (out_y
+ 1)) - 1024;
260 /* calculate ype and ypo */
262 ypo
= ype
+ (ysci
/ 64);
267 /* calculate scaling increment */
268 ysci
= (((10 * 1024 * (in_y
- out_y
- 1)) / in_y
) + 9) / 10;
270 /* calculate ype and ypo */
271 ypo
= ype
= ((ysci
+ 15) / 16);
273 /* the sequence length interval (yacl) has to be set according
274 to the prescale value, e.g. [n .. 1/2) : 0
281 yacl
= ( ysci
/ (1024 - ysci
) );
284 /* get filter coefficients for cya, cyb from table hps_v_coeff_tab */
285 cya_cyb
= hps_v_coeff_tab
[ (yacl
< 63 ? yacl
: 63 ) ].hps_coeff
;
287 /* get best match in the table of attenuations for vertical scaling */
288 v_atten
= hps_v_coeff_tab
[ (yacl
< 63 ? yacl
: 63 ) ].weight_sum
;
290 for (i
= 0; v_attenuation
[i
] != 0; i
++) {
291 if (v_attenuation
[i
] >= v_atten
)
298 /* ypo and ype swapped in spec ? */
299 *hps_v_scale
|= (yacm
<< 31) | (ysci
<< 21) | (yacl
<< 15) | (ypo
<< 8 ) | (ype
<< 1);
301 *hps_v_gain
&= ~(MASK_W0
|MASK_B2
);
302 *hps_v_gain
|= (dcgy
<< 16) | (cya_cyb
<< 0);
307 /* simple bubble-sort algorithm with duplicate elimination */
308 static int sort_and_eliminate(u32
* values
, int* count
)
310 int low
= 0, high
= 0, top
= 0, temp
= 0;
311 int cur
= 0, next
= 0;
314 if( (0 > *count
) || (NULL
== values
) ) {
318 /* bubble sort the first @count items of the array @values */
319 for( top
= *count
; top
> 0; top
--) {
320 for( low
= 0, high
= 1; high
< top
; low
++, high
++) {
321 if( values
[low
] > values
[high
] ) {
323 values
[low
] = values
[high
];
329 /* remove duplicate items */
330 for( cur
= 0, next
= 1; next
< *count
; next
++) {
331 if( values
[cur
] != values
[next
])
332 values
[++cur
] = values
[next
];
340 static void calculate_clipping_registers_rect(struct saa7146_dev
*dev
, struct saa7146_fh
*fh
,
341 struct saa7146_video_dma
*vdma2
, u32
* clip_format
, u32
* arbtr_ctrl
, enum v4l2_field field
)
343 struct saa7146_vv
*vv
= dev
->vv_data
;
344 __le32
*clipping
= vv
->d_clipping
.cpu_addr
;
346 int width
= vv
->ov
.win
.w
.width
;
347 int height
= vv
->ov
.win
.w
.height
;
348 int clipcount
= vv
->ov
.nclips
;
355 int cnt_line
= 0, cnt_pixel
= 0;
357 int x
[32], y
[32], w
[32], h
[32];
359 /* clear out memory */
360 memset(&line_list
[0], 0x00, sizeof(u32
)*32);
361 memset(&pixel_list
[0], 0x00, sizeof(u32
)*32);
362 memset(clipping
, 0x00, SAA7146_CLIPPING_MEM
);
364 /* fill the line and pixel-lists */
365 for(i
= 0; i
< clipcount
; i
++) {
366 int l
= 0, r
= 0, t
= 0, b
= 0;
368 x
[i
] = vv
->ov
.clips
[i
].c
.left
;
369 y
[i
] = vv
->ov
.clips
[i
].c
.top
;
370 w
[i
] = vv
->ov
.clips
[i
].c
.width
;
371 h
[i
] = vv
->ov
.clips
[i
].c
.height
;
374 x
[i
] += w
[i
]; w
[i
] = -w
[i
];
377 y
[i
] += h
[i
]; h
[i
] = -h
[i
];
380 w
[i
] += x
[i
]; x
[i
] = 0;
383 h
[i
] += y
[i
]; y
[i
] = 0;
385 if( 0 != vv
->vflip
) {
386 y
[i
] = height
- y
[i
] - h
[i
];
394 /* insert left/right coordinates */
395 pixel_list
[ 2*i
] = min_t(int, l
, width
);
396 pixel_list
[(2*i
)+1] = min_t(int, r
, width
);
397 /* insert top/bottom coordinates */
398 line_list
[ 2*i
] = min_t(int, t
, height
);
399 line_list
[(2*i
)+1] = min_t(int, b
, height
);
402 /* sort and eliminate lists */
403 cnt_line
= cnt_pixel
= 2*clipcount
;
404 sort_and_eliminate( &pixel_list
[0], &cnt_pixel
);
405 sort_and_eliminate( &line_list
[0], &cnt_line
);
407 /* calculate the number of used u32s */
408 numdwords
= max_t(int, (cnt_line
+1), (cnt_pixel
+1))*2;
409 numdwords
= max_t(int, 4, numdwords
);
410 numdwords
= min_t(int, 64, numdwords
);
412 /* fill up cliptable */
413 for(i
= 0; i
< cnt_pixel
; i
++) {
414 clipping
[2*i
] |= cpu_to_le32(pixel_list
[i
] << 16);
416 for(i
= 0; i
< cnt_line
; i
++) {
417 clipping
[(2*i
)+1] |= cpu_to_le32(line_list
[i
] << 16);
420 /* fill up cliptable with the display infos */
421 for(j
= 0; j
< clipcount
; j
++) {
423 for(i
= 0; i
< cnt_pixel
; i
++) {
428 if( pixel_list
[i
] < (x
[j
] + w
[j
])) {
430 if ( pixel_list
[i
] >= x
[j
] ) {
431 clipping
[2*i
] |= cpu_to_le32(1 << j
);
435 for(i
= 0; i
< cnt_line
; i
++) {
440 if( line_list
[i
] < (y
[j
] + h
[j
]) ) {
442 if( line_list
[i
] >= y
[j
] ) {
443 clipping
[(2*i
)+1] |= cpu_to_le32(1 << j
);
449 /* adjust arbitration control register */
450 *arbtr_ctrl
&= 0xffff00ff;
451 *arbtr_ctrl
|= 0x00001c00;
453 vdma2
->base_even
= vv
->d_clipping
.dma_handle
;
454 vdma2
->base_odd
= vv
->d_clipping
.dma_handle
;
455 vdma2
->prot_addr
= vv
->d_clipping
.dma_handle
+((sizeof(u32
))*(numdwords
));
456 vdma2
->base_page
= 0x04;
458 vdma2
->num_line_byte
= (0 << 16 | (sizeof(u32
))*(numdwords
-1) );
460 /* set clipping-mode. this depends on the field(s) used */
461 *clip_format
&= 0xfffffff7;
462 if (V4L2_FIELD_HAS_BOTH(field
)) {
463 *clip_format
|= 0x00000008;
465 *clip_format
|= 0x00000000;
469 /* disable clipping */
470 static void saa7146_disable_clipping(struct saa7146_dev
*dev
)
472 u32 clip_format
= saa7146_read(dev
, CLIP_FORMAT_CTRL
);
474 /* mask out relevant bits (=lower word)*/
475 clip_format
&= MASK_W1
;
477 /* upload clipping-registers*/
478 saa7146_write(dev
, CLIP_FORMAT_CTRL
,clip_format
);
479 saa7146_write(dev
, MC2
, (MASK_05
| MASK_21
));
481 /* disable video dma2 */
482 saa7146_write(dev
, MC1
, MASK_21
);
485 static void saa7146_set_clipping_rect(struct saa7146_fh
*fh
)
487 struct saa7146_dev
*dev
= fh
->dev
;
488 struct saa7146_vv
*vv
= dev
->vv_data
;
489 enum v4l2_field field
= vv
->ov
.win
.field
;
490 struct saa7146_video_dma vdma2
;
494 /* check clipcount, disable clipping if clipcount == 0*/
495 if (vv
->ov
.nclips
== 0) {
496 saa7146_disable_clipping(dev
);
500 clip_format
= saa7146_read(dev
, CLIP_FORMAT_CTRL
);
501 arbtr_ctrl
= saa7146_read(dev
, PCI_BT_V1
);
503 calculate_clipping_registers_rect(dev
, fh
, &vdma2
, &clip_format
, &arbtr_ctrl
, field
);
505 /* set clipping format */
506 clip_format
&= 0xffff0008;
507 clip_format
|= (SAA7146_CLIPPING_RECT
<< 4);
509 /* prepare video dma2 */
510 saa7146_write(dev
, BASE_EVEN2
, vdma2
.base_even
);
511 saa7146_write(dev
, BASE_ODD2
, vdma2
.base_odd
);
512 saa7146_write(dev
, PROT_ADDR2
, vdma2
.prot_addr
);
513 saa7146_write(dev
, BASE_PAGE2
, vdma2
.base_page
);
514 saa7146_write(dev
, PITCH2
, vdma2
.pitch
);
515 saa7146_write(dev
, NUM_LINE_BYTE2
, vdma2
.num_line_byte
);
517 /* prepare the rest */
518 saa7146_write(dev
, CLIP_FORMAT_CTRL
,clip_format
);
519 saa7146_write(dev
, PCI_BT_V1
, arbtr_ctrl
);
521 /* upload clip_control-register, clipping-registers, enable video dma2 */
522 saa7146_write(dev
, MC2
, (MASK_05
| MASK_21
| MASK_03
| MASK_19
));
523 saa7146_write(dev
, MC1
, (MASK_05
| MASK_21
));
526 static void saa7146_set_window(struct saa7146_dev
*dev
, int width
, int height
, enum v4l2_field field
)
528 struct saa7146_vv
*vv
= dev
->vv_data
;
530 int source
= vv
->current_hps_source
;
531 int sync
= vv
->current_hps_sync
;
533 u32 hps_v_scale
= 0, hps_v_gain
= 0, hps_ctrl
= 0, hps_h_prescale
= 0, hps_h_scale
= 0;
535 /* set vertical scale */
536 hps_v_scale
= 0; /* all bits get set by the function-call */
537 hps_v_gain
= 0; /* fixme: saa7146_read(dev, HPS_V_GAIN);*/
538 calculate_v_scale_registers(dev
, field
, vv
->standard
->v_field
*2, height
, &hps_v_scale
, &hps_v_gain
);
540 /* set horizontal scale */
542 hps_h_prescale
= 0; /* all bits get set in the function */
544 calculate_h_scale_registers(dev
, vv
->standard
->h_pixels
, width
, vv
->hflip
, &hps_ctrl
, &hps_v_gain
, &hps_h_prescale
, &hps_h_scale
);
546 /* set hyo and hxo */
547 calculate_hxo_and_hyo(vv
, &hps_h_scale
, &hps_ctrl
);
548 calculate_hps_source_and_sync(dev
, source
, sync
, &hps_ctrl
);
550 /* write out new register contents */
551 saa7146_write(dev
, HPS_V_SCALE
, hps_v_scale
);
552 saa7146_write(dev
, HPS_V_GAIN
, hps_v_gain
);
553 saa7146_write(dev
, HPS_CTRL
, hps_ctrl
);
554 saa7146_write(dev
, HPS_H_PRESCALE
,hps_h_prescale
);
555 saa7146_write(dev
, HPS_H_SCALE
, hps_h_scale
);
557 /* upload shadow-ram registers */
558 saa7146_write(dev
, MC2
, (MASK_05
| MASK_06
| MASK_21
| MASK_22
) );
561 /* calculate the new memory offsets for a desired position */
562 static void saa7146_set_position(struct saa7146_dev
*dev
, int w_x
, int w_y
, int w_height
, enum v4l2_field field
, u32 pixelformat
)
564 struct saa7146_vv
*vv
= dev
->vv_data
;
565 struct saa7146_format
*sfmt
= saa7146_format_by_fourcc(dev
, pixelformat
);
567 int b_depth
= vv
->ov_fmt
->depth
;
568 int b_bpl
= vv
->ov_fb
.fmt
.bytesperline
;
569 /* The unsigned long cast is to remove a 64-bit compile warning since
570 it looks like a 64-bit address is cast to a 32-bit value, even
571 though the base pointer is really a 32-bit physical address that
572 goes into a 32-bit DMA register.
573 FIXME: might not work on some 64-bit platforms, but see the FIXME
574 in struct v4l2_framebuffer (videodev2.h) for that.
576 u32 base
= (u32
)(unsigned long)vv
->ov_fb
.base
;
578 struct saa7146_video_dma vdma1
;
580 /* calculate memory offsets for picture, look if we shall top-down-flip */
581 vdma1
.pitch
= 2*b_bpl
;
582 if ( 0 == vv
->vflip
) {
583 vdma1
.base_even
= base
+ (w_y
* (vdma1
.pitch
/2)) + (w_x
* (b_depth
/ 8));
584 vdma1
.base_odd
= vdma1
.base_even
+ (vdma1
.pitch
/ 2);
585 vdma1
.prot_addr
= vdma1
.base_even
+ (w_height
* (vdma1
.pitch
/ 2));
588 vdma1
.base_even
= base
+ ((w_y
+w_height
) * (vdma1
.pitch
/2)) + (w_x
* (b_depth
/ 8));
589 vdma1
.base_odd
= vdma1
.base_even
- (vdma1
.pitch
/ 2);
590 vdma1
.prot_addr
= vdma1
.base_odd
- (w_height
* (vdma1
.pitch
/ 2));
593 if (V4L2_FIELD_HAS_BOTH(field
)) {
594 } else if (field
== V4L2_FIELD_ALTERNATE
) {
596 vdma1
.base_odd
= vdma1
.prot_addr
;
598 } else if (field
== V4L2_FIELD_TOP
) {
599 vdma1
.base_odd
= vdma1
.prot_addr
;
601 } else if (field
== V4L2_FIELD_BOTTOM
) {
602 vdma1
.base_odd
= vdma1
.base_even
;
603 vdma1
.base_even
= vdma1
.prot_addr
;
607 if ( 0 != vv
->vflip
) {
611 vdma1
.base_page
= sfmt
->swap
;
612 vdma1
.num_line_byte
= (vv
->standard
->v_field
<<16)+vv
->standard
->h_pixels
;
614 saa7146_write_out_dma(dev
, 1, &vdma1
);
617 static void saa7146_set_output_format(struct saa7146_dev
*dev
, unsigned long palette
)
619 u32 clip_format
= saa7146_read(dev
, CLIP_FORMAT_CTRL
);
621 /* call helper function */
622 calculate_output_format_register(dev
,palette
,&clip_format
);
624 /* update the hps registers */
625 saa7146_write(dev
, CLIP_FORMAT_CTRL
, clip_format
);
626 saa7146_write(dev
, MC2
, (MASK_05
| MASK_21
));
629 /* select input-source */
630 void saa7146_set_hps_source_and_sync(struct saa7146_dev
*dev
, int source
, int sync
)
632 struct saa7146_vv
*vv
= dev
->vv_data
;
636 hps_ctrl
= saa7146_read(dev
, HPS_CTRL
);
638 hps_ctrl
&= ~( MASK_31
| MASK_30
| MASK_28
);
639 hps_ctrl
|= (source
<< 30) | (sync
<< 28);
641 /* write back & upload register */
642 saa7146_write(dev
, HPS_CTRL
, hps_ctrl
);
643 saa7146_write(dev
, MC2
, (MASK_05
| MASK_21
));
645 vv
->current_hps_source
= source
;
646 vv
->current_hps_sync
= sync
;
648 EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync
);
650 int saa7146_enable_overlay(struct saa7146_fh
*fh
)
652 struct saa7146_dev
*dev
= fh
->dev
;
653 struct saa7146_vv
*vv
= dev
->vv_data
;
655 saa7146_set_window(dev
, vv
->ov
.win
.w
.width
, vv
->ov
.win
.w
.height
, vv
->ov
.win
.field
);
656 saa7146_set_position(dev
, vv
->ov
.win
.w
.left
, vv
->ov
.win
.w
.top
, vv
->ov
.win
.w
.height
, vv
->ov
.win
.field
, vv
->ov_fmt
->pixelformat
);
657 saa7146_set_output_format(dev
, vv
->ov_fmt
->trans
);
658 saa7146_set_clipping_rect(fh
);
660 /* enable video dma1 */
661 saa7146_write(dev
, MC1
, (MASK_06
| MASK_22
));
665 void saa7146_disable_overlay(struct saa7146_fh
*fh
)
667 struct saa7146_dev
*dev
= fh
->dev
;
669 /* disable clipping + video dma1 */
670 saa7146_disable_clipping(dev
);
671 saa7146_write(dev
, MC1
, MASK_22
);
674 void saa7146_write_out_dma(struct saa7146_dev
* dev
, int which
, struct saa7146_video_dma
* vdma
)
678 if( which
< 1 || which
> 3) {
682 /* calculate starting address */
683 where
= (which
-1)*0x18;
685 saa7146_write(dev
, where
, vdma
->base_odd
);
686 saa7146_write(dev
, where
+0x04, vdma
->base_even
);
687 saa7146_write(dev
, where
+0x08, vdma
->prot_addr
);
688 saa7146_write(dev
, where
+0x0c, vdma
->pitch
);
689 saa7146_write(dev
, where
+0x10, vdma
->base_page
);
690 saa7146_write(dev
, where
+0x14, vdma
->num_line_byte
);
693 saa7146_write(dev
, MC2
, (MASK_02
<<(which
-1))|(MASK_18
<<(which
-1)));
695 printk("vdma%d.base_even: 0x%08x\n", which,vdma->base_even);
696 printk("vdma%d.base_odd: 0x%08x\n", which,vdma->base_odd);
697 printk("vdma%d.prot_addr: 0x%08x\n", which,vdma->prot_addr);
698 printk("vdma%d.base_page: 0x%08x\n", which,vdma->base_page);
699 printk("vdma%d.pitch: 0x%08x\n", which,vdma->pitch);
700 printk("vdma%d.num_line_byte: 0x%08x\n", which,vdma->num_line_byte);
704 static int calculate_video_dma_grab_packed(struct saa7146_dev
* dev
, struct saa7146_buf
*buf
)
706 struct saa7146_vv
*vv
= dev
->vv_data
;
707 struct saa7146_video_dma vdma1
;
709 struct saa7146_format
*sfmt
= saa7146_format_by_fourcc(dev
,buf
->fmt
->pixelformat
);
711 int width
= buf
->fmt
->width
;
712 int height
= buf
->fmt
->height
;
713 int bytesperline
= buf
->fmt
->bytesperline
;
714 enum v4l2_field field
= buf
->fmt
->field
;
716 int depth
= sfmt
->depth
;
718 DEB_CAP("[size=%dx%d,fields=%s]\n",
719 width
, height
, v4l2_field_names
[field
]);
721 if( bytesperline
!= 0) {
722 vdma1
.pitch
= bytesperline
*2;
724 vdma1
.pitch
= (width
*depth
*2)/8;
726 vdma1
.num_line_byte
= ((vv
->standard
->v_field
<<16) + vv
->standard
->h_pixels
);
727 vdma1
.base_page
= buf
->pt
[0].dma
| ME1
| sfmt
->swap
;
729 if( 0 != vv
->vflip
) {
730 vdma1
.prot_addr
= buf
->pt
[0].offset
;
731 vdma1
.base_even
= buf
->pt
[0].offset
+(vdma1
.pitch
/2)*height
;
732 vdma1
.base_odd
= vdma1
.base_even
- (vdma1
.pitch
/2);
734 vdma1
.base_even
= buf
->pt
[0].offset
;
735 vdma1
.base_odd
= vdma1
.base_even
+ (vdma1
.pitch
/2);
736 vdma1
.prot_addr
= buf
->pt
[0].offset
+(vdma1
.pitch
/2)*height
;
739 if (V4L2_FIELD_HAS_BOTH(field
)) {
740 } else if (field
== V4L2_FIELD_ALTERNATE
) {
742 if ( vv
->last_field
== V4L2_FIELD_TOP
) {
743 vdma1
.base_odd
= vdma1
.prot_addr
;
745 } else if ( vv
->last_field
== V4L2_FIELD_BOTTOM
) {
746 vdma1
.base_odd
= vdma1
.base_even
;
747 vdma1
.base_even
= vdma1
.prot_addr
;
750 } else if (field
== V4L2_FIELD_TOP
) {
751 vdma1
.base_odd
= vdma1
.prot_addr
;
753 } else if (field
== V4L2_FIELD_BOTTOM
) {
754 vdma1
.base_odd
= vdma1
.base_even
;
755 vdma1
.base_even
= vdma1
.prot_addr
;
759 if( 0 != vv
->vflip
) {
763 saa7146_write_out_dma(dev
, 1, &vdma1
);
767 static int calc_planar_422(struct saa7146_vv
*vv
, struct saa7146_buf
*buf
, struct saa7146_video_dma
*vdma2
, struct saa7146_video_dma
*vdma3
)
769 int height
= buf
->fmt
->height
;
770 int width
= buf
->fmt
->width
;
772 vdma2
->pitch
= width
;
773 vdma3
->pitch
= width
;
775 /* fixme: look at bytesperline! */
777 if( 0 != vv
->vflip
) {
778 vdma2
->prot_addr
= buf
->pt
[1].offset
;
779 vdma2
->base_even
= ((vdma2
->pitch
/2)*height
)+buf
->pt
[1].offset
;
780 vdma2
->base_odd
= vdma2
->base_even
- (vdma2
->pitch
/2);
782 vdma3
->prot_addr
= buf
->pt
[2].offset
;
783 vdma3
->base_even
= ((vdma3
->pitch
/2)*height
)+buf
->pt
[2].offset
;
784 vdma3
->base_odd
= vdma3
->base_even
- (vdma3
->pitch
/2);
786 vdma3
->base_even
= buf
->pt
[2].offset
;
787 vdma3
->base_odd
= vdma3
->base_even
+ (vdma3
->pitch
/2);
788 vdma3
->prot_addr
= (vdma3
->pitch
/2)*height
+buf
->pt
[2].offset
;
790 vdma2
->base_even
= buf
->pt
[1].offset
;
791 vdma2
->base_odd
= vdma2
->base_even
+ (vdma2
->pitch
/2);
792 vdma2
->prot_addr
= (vdma2
->pitch
/2)*height
+buf
->pt
[1].offset
;
798 static int calc_planar_420(struct saa7146_vv
*vv
, struct saa7146_buf
*buf
, struct saa7146_video_dma
*vdma2
, struct saa7146_video_dma
*vdma3
)
800 int height
= buf
->fmt
->height
;
801 int width
= buf
->fmt
->width
;
803 vdma2
->pitch
= width
/2;
804 vdma3
->pitch
= width
/2;
806 if( 0 != vv
->vflip
) {
807 vdma2
->prot_addr
= buf
->pt
[2].offset
;
808 vdma2
->base_even
= ((vdma2
->pitch
/2)*height
)+buf
->pt
[2].offset
;
809 vdma2
->base_odd
= vdma2
->base_even
- (vdma2
->pitch
/2);
811 vdma3
->prot_addr
= buf
->pt
[1].offset
;
812 vdma3
->base_even
= ((vdma3
->pitch
/2)*height
)+buf
->pt
[1].offset
;
813 vdma3
->base_odd
= vdma3
->base_even
- (vdma3
->pitch
/2);
816 vdma3
->base_even
= buf
->pt
[2].offset
;
817 vdma3
->base_odd
= vdma3
->base_even
+ (vdma3
->pitch
);
818 vdma3
->prot_addr
= (vdma3
->pitch
/2)*height
+buf
->pt
[2].offset
;
820 vdma2
->base_even
= buf
->pt
[1].offset
;
821 vdma2
->base_odd
= vdma2
->base_even
+ (vdma2
->pitch
);
822 vdma2
->prot_addr
= (vdma2
->pitch
/2)*height
+buf
->pt
[1].offset
;
827 static int calculate_video_dma_grab_planar(struct saa7146_dev
* dev
, struct saa7146_buf
*buf
)
829 struct saa7146_vv
*vv
= dev
->vv_data
;
830 struct saa7146_video_dma vdma1
;
831 struct saa7146_video_dma vdma2
;
832 struct saa7146_video_dma vdma3
;
834 struct saa7146_format
*sfmt
= saa7146_format_by_fourcc(dev
,buf
->fmt
->pixelformat
);
836 int width
= buf
->fmt
->width
;
837 int height
= buf
->fmt
->height
;
838 enum v4l2_field field
= buf
->fmt
->field
;
840 BUG_ON(0 == buf
->pt
[0].dma
);
841 BUG_ON(0 == buf
->pt
[1].dma
);
842 BUG_ON(0 == buf
->pt
[2].dma
);
844 DEB_CAP("[size=%dx%d,fields=%s]\n",
845 width
, height
, v4l2_field_names
[field
]);
847 /* fixme: look at bytesperline! */
849 /* fixme: what happens for user space buffers here?. The offsets are
850 most likely wrong, this version here only works for page-aligned
851 buffers, modifications to the pagetable-functions are necessary...*/
853 vdma1
.pitch
= width
*2;
854 vdma1
.num_line_byte
= ((vv
->standard
->v_field
<<16) + vv
->standard
->h_pixels
);
855 vdma1
.base_page
= buf
->pt
[0].dma
| ME1
;
857 if( 0 != vv
->vflip
) {
858 vdma1
.prot_addr
= buf
->pt
[0].offset
;
859 vdma1
.base_even
= ((vdma1
.pitch
/2)*height
)+buf
->pt
[0].offset
;
860 vdma1
.base_odd
= vdma1
.base_even
- (vdma1
.pitch
/2);
862 vdma1
.base_even
= buf
->pt
[0].offset
;
863 vdma1
.base_odd
= vdma1
.base_even
+ (vdma1
.pitch
/2);
864 vdma1
.prot_addr
= (vdma1
.pitch
/2)*height
+buf
->pt
[0].offset
;
867 vdma2
.num_line_byte
= 0; /* unused */
868 vdma2
.base_page
= buf
->pt
[1].dma
| ME1
;
870 vdma3
.num_line_byte
= 0; /* unused */
871 vdma3
.base_page
= buf
->pt
[2].dma
| ME1
;
873 switch( sfmt
->depth
) {
875 calc_planar_420(vv
,buf
,&vdma2
,&vdma3
);
879 calc_planar_422(vv
,buf
,&vdma2
,&vdma3
);
887 if (V4L2_FIELD_HAS_BOTH(field
)) {
888 } else if (field
== V4L2_FIELD_ALTERNATE
) {
890 vdma1
.base_odd
= vdma1
.prot_addr
;
892 vdma2
.base_odd
= vdma2
.prot_addr
;
894 vdma3
.base_odd
= vdma3
.prot_addr
;
896 } else if (field
== V4L2_FIELD_TOP
) {
897 vdma1
.base_odd
= vdma1
.prot_addr
;
899 vdma2
.base_odd
= vdma2
.prot_addr
;
901 vdma3
.base_odd
= vdma3
.prot_addr
;
903 } else if (field
== V4L2_FIELD_BOTTOM
) {
904 vdma1
.base_odd
= vdma1
.base_even
;
905 vdma1
.base_even
= vdma1
.prot_addr
;
907 vdma2
.base_odd
= vdma2
.base_even
;
908 vdma2
.base_even
= vdma2
.prot_addr
;
910 vdma3
.base_odd
= vdma3
.base_even
;
911 vdma3
.base_even
= vdma3
.prot_addr
;
915 if( 0 != vv
->vflip
) {
921 saa7146_write_out_dma(dev
, 1, &vdma1
);
922 if( (sfmt
->flags
& FORMAT_BYTE_SWAP
) != 0 ) {
923 saa7146_write_out_dma(dev
, 3, &vdma2
);
924 saa7146_write_out_dma(dev
, 2, &vdma3
);
926 saa7146_write_out_dma(dev
, 2, &vdma2
);
927 saa7146_write_out_dma(dev
, 3, &vdma3
);
932 static void program_capture_engine(struct saa7146_dev
*dev
, int planar
)
934 struct saa7146_vv
*vv
= dev
->vv_data
;
937 unsigned long e_wait
= vv
->current_hps_sync
== SAA7146_HPS_SYNC_PORT_A
? CMD_E_FID_A
: CMD_E_FID_B
;
938 unsigned long o_wait
= vv
->current_hps_sync
== SAA7146_HPS_SYNC_PORT_A
? CMD_O_FID_A
: CMD_O_FID_B
;
940 /* wait for o_fid_a/b / e_fid_a/b toggle only if rps register 0 is not set*/
941 WRITE_RPS0(CMD_PAUSE
| CMD_OAN
| CMD_SIG0
| o_wait
);
942 WRITE_RPS0(CMD_PAUSE
| CMD_OAN
| CMD_SIG0
| e_wait
);
944 /* set rps register 0 */
945 WRITE_RPS0(CMD_WR_REG
| (1 << 8) | (MC2
/4));
946 WRITE_RPS0(MASK_27
| MASK_11
);
948 /* turn on video-dma1 */
949 WRITE_RPS0(CMD_WR_REG_MASK
| (MC1
/4));
950 WRITE_RPS0(MASK_06
| MASK_22
); /* => mask */
951 WRITE_RPS0(MASK_06
| MASK_22
); /* => values */
953 /* turn on video-dma2 */
954 WRITE_RPS0(CMD_WR_REG_MASK
| (MC1
/4));
955 WRITE_RPS0(MASK_05
| MASK_21
); /* => mask */
956 WRITE_RPS0(MASK_05
| MASK_21
); /* => values */
958 /* turn on video-dma3 */
959 WRITE_RPS0(CMD_WR_REG_MASK
| (MC1
/4));
960 WRITE_RPS0(MASK_04
| MASK_20
); /* => mask */
961 WRITE_RPS0(MASK_04
| MASK_20
); /* => values */
964 /* wait for o_fid_a/b / e_fid_a/b toggle */
965 if ( vv
->last_field
== V4L2_FIELD_INTERLACED
) {
966 WRITE_RPS0(CMD_PAUSE
| o_wait
);
967 WRITE_RPS0(CMD_PAUSE
| e_wait
);
968 } else if ( vv
->last_field
== V4L2_FIELD_TOP
) {
969 WRITE_RPS0(CMD_PAUSE
| (vv
->current_hps_sync
== SAA7146_HPS_SYNC_PORT_A
? MASK_10
: MASK_09
));
970 WRITE_RPS0(CMD_PAUSE
| o_wait
);
971 } else if ( vv
->last_field
== V4L2_FIELD_BOTTOM
) {
972 WRITE_RPS0(CMD_PAUSE
| (vv
->current_hps_sync
== SAA7146_HPS_SYNC_PORT_A
? MASK_10
: MASK_09
));
973 WRITE_RPS0(CMD_PAUSE
| e_wait
);
976 /* turn off video-dma1 */
977 WRITE_RPS0(CMD_WR_REG_MASK
| (MC1
/4));
978 WRITE_RPS0(MASK_22
| MASK_06
); /* => mask */
979 WRITE_RPS0(MASK_22
); /* => values */
981 /* turn off video-dma2 */
982 WRITE_RPS0(CMD_WR_REG_MASK
| (MC1
/4));
983 WRITE_RPS0(MASK_05
| MASK_21
); /* => mask */
984 WRITE_RPS0(MASK_21
); /* => values */
986 /* turn off video-dma3 */
987 WRITE_RPS0(CMD_WR_REG_MASK
| (MC1
/4));
988 WRITE_RPS0(MASK_04
| MASK_20
); /* => mask */
989 WRITE_RPS0(MASK_20
); /* => values */
992 /* generate interrupt */
993 WRITE_RPS0(CMD_INTERRUPT
);
996 WRITE_RPS0(CMD_STOP
);
999 void saa7146_set_capture(struct saa7146_dev
*dev
, struct saa7146_buf
*buf
, struct saa7146_buf
*next
)
1001 struct saa7146_format
*sfmt
= saa7146_format_by_fourcc(dev
,buf
->fmt
->pixelformat
);
1002 struct saa7146_vv
*vv
= dev
->vv_data
;
1003 u32 vdma1_prot_addr
;
1005 DEB_CAP("buf:%p, next:%p\n", buf
, next
);
1007 vdma1_prot_addr
= saa7146_read(dev
, PROT_ADDR1
);
1008 if( 0 == vdma1_prot_addr
) {
1009 /* clear out beginning of streaming bit (rps register 0)*/
1010 DEB_CAP("forcing sync to new frame\n");
1011 saa7146_write(dev
, MC2
, MASK_27
);
1014 saa7146_set_window(dev
, buf
->fmt
->width
, buf
->fmt
->height
, buf
->fmt
->field
);
1015 saa7146_set_output_format(dev
, sfmt
->trans
);
1016 saa7146_disable_clipping(dev
);
1018 if ( vv
->last_field
== V4L2_FIELD_INTERLACED
) {
1019 } else if ( vv
->last_field
== V4L2_FIELD_TOP
) {
1020 vv
->last_field
= V4L2_FIELD_BOTTOM
;
1021 } else if ( vv
->last_field
== V4L2_FIELD_BOTTOM
) {
1022 vv
->last_field
= V4L2_FIELD_TOP
;
1025 if( 0 != IS_PLANAR(sfmt
->trans
)) {
1026 calculate_video_dma_grab_planar(dev
, buf
);
1027 program_capture_engine(dev
,1);
1029 calculate_video_dma_grab_packed(dev
, buf
);
1030 program_capture_engine(dev
,0);
1034 printk("vdma%d.base_even: 0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1));
1035 printk("vdma%d.base_odd: 0x%08x\n", 1,saa7146_read(dev,BASE_ODD1));
1036 printk("vdma%d.prot_addr: 0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1));
1037 printk("vdma%d.base_page: 0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1));
1038 printk("vdma%d.pitch: 0x%08x\n", 1,saa7146_read(dev,PITCH1));
1039 printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1));
1040 printk("vdma%d => vptr : 0x%08x\n", 1,saa7146_read(dev,PCI_VDP1));
1043 /* write the address of the rps-program */
1044 saa7146_write(dev
, RPS_ADDR0
, dev
->d_rps0
.dma_handle
);
1047 saa7146_write(dev
, MC1
, (MASK_12
| MASK_28
));