summaryrefslogtreecommitdiff
path: root/linux/drivers/media/dvb/av7110/saa7146.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/dvb/av7110/saa7146.c')
-rw-r--r--linux/drivers/media/dvb/av7110/saa7146.c1662
1 files changed, 0 insertions, 1662 deletions
diff --git a/linux/drivers/media/dvb/av7110/saa7146.c b/linux/drivers/media/dvb/av7110/saa7146.c
deleted file mode 100644
index 93fa074ad..000000000
--- a/linux/drivers/media/dvb/av7110/saa7146.c
+++ /dev/null
@@ -1,1662 +0,0 @@
-/*
- the api- and os-independet parts of the saa7146 device driver
-
- Copyright (C) 1998,1999 Michael Hunold <michael@mihu.de>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "saa7146_defs.h"
-
-#define TRUNC(val,max) ((val) < (max) ? (val) : (max))
-
-#ifdef __COMPILE_SAA7146__
-
-struct saa7146_modes_constants
- modes_constants[] = {
- { V_OFFSET_PAL, V_FIELD_PAL, V_ACTIVE_LINES_PAL,
- H_OFFSET_PAL, H_PIXELS_PAL, H_PIXELS_PAL+1,
- V_ACTIVE_LINES_PAL, 1024 }, /* PAL values */
- { V_OFFSET_NTSC, V_FIELD_NTSC, V_ACTIVE_LINES_NTSC,
- H_OFFSET_NTSC, H_PIXELS_NTSC, H_PIXELS_NTSC+1,
- V_ACTIVE_LINES_NTSC, 1024 }, /* NTSC values */
- { 0,0,0,0,0,0,0,0 }, /* secam values */
- { 0,288,576,
- 0,188*4,188*4+1,
- 288,188*4 } /* TS values */
-};
-
-/* -----------------------------------------------------------------------------------------
- helper functions for the calculation of the horizontal- and vertical scaling registers,
- clip-format-register etc ...
- these functions take pointers to the (most-likely read-out original-values) and manipulate
- them according to the requested new scaling parameters.
- ----------------------------------------------------------------------------------------- */
-
-/* hps_coeff used for CXY and CXUV; scale 1/1 -> scale 1/64 */
-struct {
- u16 hps_coeff;
- u16 weight_sum;
-} hps_h_coeff_tab [] = {
- {0x00, 2}, {0x02, 4}, {0x00, 4}, {0x06, 8}, {0x02, 8},
- {0x08, 8}, {0x00, 8}, {0x1E, 16}, {0x0E, 8}, {0x26, 8},
- {0x06, 8}, {0x42, 8}, {0x02, 8}, {0x80, 8}, {0x00, 8},
- {0xFE, 16}, {0xFE, 8}, {0x7E, 8}, {0x7E, 8}, {0x3E, 8},
- {0x3E, 8}, {0x1E, 8}, {0x1E, 8}, {0x0E, 8}, {0x0E, 8},
- {0x06, 8}, {0x06, 8}, {0x02, 8}, {0x02, 8}, {0x00, 8},
- {0x00, 8}, {0xFE, 16}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8},
- {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8},
- {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8},
- {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0x7E, 8},
- {0x7E, 8}, {0x3E, 8}, {0x3E, 8}, {0x1E, 8}, {0x1E, 8},
- {0x0E, 8}, {0x0E, 8}, {0x06, 8}, {0x06, 8}, {0x02, 8},
- {0x02, 8}, {0x00, 8}, {0x00, 8}, {0xFE, 16}
-};
-
-/* table of attenuation values for horizontal scaling */
-u8 h_attenuation[] = { 1, 2, 4, 8, 2, 4, 8, 16, 0};
-
-int calculate_h_scale_registers(struct saa7146* saa, u32 in_x, u32 out_x, int flip_lr, u32* hps_ctrl, u32* hps_v_gain, u32* hps_h_prescale, u32* hps_h_scale)
-{
- /* horizontal prescaler */
- u32 dcgx = 0, xpsc = 0, xacm = 0, cxy = 0, cxuv = 0;
- /* horizontal scaler */
- u32 xim = 0, xp = 0, xsci =0;
- /* vertical scale & gain */
- u32 pfuv = 0;
- /* helper variables */
- u32 h_atten = 0, i = 0;
-
- if ( 0 == out_x ) {
- printk("saa7146: ==> calculate_h_scale_registers: invalid value (=0).\n");
- return -EINVAL;
- }
-
- /* mask out vanity-bit */
- *hps_ctrl &= ~MASK_29;
-
- /* calculate prescale-(xspc)-value: [n .. 1/2) : 1
- [1/2 .. 1/3) : 2
- [1/3 .. 1/4) : 3
- ... */
- if (in_x > out_x) {
- xpsc = in_x / out_x;
- } else {
- /* zooming */
- xpsc = 1;
- }
-
- /* if flip_lr-bit is set, number of pixels after horizontal prescaling must be < 384 */
- if ( 0 != flip_lr ) {
- /* set vanity bit */
- *hps_ctrl |= MASK_29;
-
- while (in_x / xpsc >= 384 )
- xpsc++;
- }
- /* if zooming is wanted, number of pixels after horizontal prescaling must be < 768 */
- else {
- while ( in_x / xpsc >= 768 )
- xpsc++;
- }
-
- /* maximum prescale is 64 (p.69) */
- if ( xpsc > 64 )
- xpsc = 64;
-
- /* keep xacm clear*/
- xacm = 0;
-
- /* set horizontal filter parameters (CXY = CXUV) */
- cxy = hps_h_coeff_tab[TRUNC(xpsc - 1, 63)].hps_coeff;
- cxuv = cxy;
-
- /* calculate and set horizontal fine scale (xsci) */
-
- /* bypass the horizontal scaler ? */
- if ( (in_x == out_x) && ( 1 == xpsc ) )
- xsci = 0x400;
- else
- xsci = ( (1024 * in_x) / (out_x * xpsc) ) + xpsc;
-
- /* set start phase for horizontal fine scale (xp) to 0 */
- xp = 0;
-
- /* set xim, if we bypass the horizontal scaler */
- if ( 0x400 == xsci )
- xim = 1;
- else
- xim = 0;
-
- /* if the prescaler is bypassed, enable horizontal accumulation mode (xacm)
- and clear dcgx */
- if( 1 == xpsc ) {
- xacm = 1;
- dcgx = 0;
- } else {
- xacm = 0;
- /* get best match in the table of attenuations for horizontal scaling */
- h_atten = hps_h_coeff_tab[TRUNC(xpsc - 1, 63)].weight_sum;
-
- for (i = 0; h_attenuation[i] != 0; i++) {
- if (h_attenuation[i] >= h_atten)
- break;
- }
-
- dcgx = i;
- }
-
- /* the horizontal scaling increment controls the UV filter to reduce the bandwith to
- improve the display quality, so set it ... */
- if ( xsci == 0x400)
- pfuv = 0x00;
- else if ( xsci < 0x600)
- pfuv = 0x01;
- else if ( xsci < 0x680)
- pfuv = 0x11;
- else if ( xsci < 0x700)
- pfuv = 0x22;
- else
- pfuv = 0x33;
-
-
- *hps_v_gain &= MASK_W0|MASK_B2;
- *hps_v_gain |= (pfuv << 24);
-
- *hps_h_scale &= ~(MASK_W1 | 0xf000);
- *hps_h_scale |= (xim << 31) | (xp << 24) | (xsci << 12);
-
- *hps_h_prescale |= (dcgx << 27) | ((xpsc-1) << 18) | (xacm << 17) | (cxy << 8) | (cxuv << 0);
-
- return 0;
-}
-
-struct {
- u16 hps_coeff;
- u16 weight_sum;
-} hps_v_coeff_tab [] = {
- {0x0100, 2}, {0x0102, 4}, {0x0300, 4}, {0x0106, 8},
- {0x0502, 8}, {0x0708, 8}, {0x0F00, 8}, {0x011E, 16},
- {0x110E, 16}, {0x1926, 16}, {0x3906, 16}, {0x3D42, 16},
- {0x7D02, 16}, {0x7F80, 16}, {0xFF00, 16}, {0x01FE, 32},
- {0x01FE, 32}, {0x817E, 32}, {0x817E, 32}, {0xC13E, 32},
- {0xC13E, 32}, {0xE11E, 32}, {0xE11E, 32}, {0xF10E, 32},
- {0xF10E, 32}, {0xF906, 32}, {0xF906, 32}, {0xFD02, 32},
- {0xFD02, 32}, {0xFF00, 32}, {0xFF00, 32}, {0x01FE, 64},
- {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64},
- {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64},
- {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64},
- {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64},
- {0x01FE, 64}, {0x817E, 64}, {0x817E, 64}, {0xC13E, 64},
- {0xC13E, 64}, {0xE11E, 64}, {0xE11E, 64}, {0xF10E, 64},
- {0xF10E, 64}, {0xF906, 64}, {0xF906, 64}, {0xFD02, 64},
- {0xFD02, 64}, {0xFF00, 64}, {0xFF00, 64}, {0x01FE, 128}
-};
-
-/* table of attenuation values for vertical scaling */
-u16 v_attenuation[] = { 2, 4, 8, 16, 32, 64, 128, 256, 0};
-
-int calculate_v_scale_registers(struct saa7146* saa, u32 in_y, u32 out_y, u32* hps_v_scale, u32* hps_v_gain)
-{
- u32 yacm = 0, ysci = 0, yacl = 0, ypo = 0, ype = 0; /* vertical scaling */
- u32 dcgy = 0, cya_cyb = 0; /* vertical scale & gain */
-
- u32 v_atten = 0, i = 0; /* helper variables */
-
- /* error, if vertical zooming */
- if ( in_y < out_y ) {
- printk("saa7146: ==> calculate_v_scale_registers: we cannot do vertical zooming.\n");
- return -EINVAL;
- }
-
- /* linear phase interpolation may be used if scaling is between 1 and 1/2
- or scaling is between 1/2 and 1/4 (if interlace is set; see below) */
- if( ((2*out_y) >= in_y) || (((4*out_y) >= in_y) && saa->interlace != 0)) {
-
- /* convention: if scaling is between 1/2 and 1/4 we only use
- the even lines, the odd lines get discarded (see function move_to)
- if interlace is set */
- if( saa->interlace != 0 && (out_y*4) >= in_y && (out_y*2) <= in_y)
- out_y *= 2;
-
- yacm = 0;
- yacl = 0;
- cya_cyb = 0x00ff;
-
- /* calculate scaling increment */
- if ( in_y > out_y )
- ysci = ((1024 * in_y) / (out_y + 1)) - 1024;
- else
- ysci = 0;
-
- dcgy = 0;
-
- /* calculate ype and ypo */
- if (saa->interlace !=0) {
-
- /* Special case for interlaced input */
-
- /* See Philips SAA7146A Product Spec (page 75): */
- /* "For interlaced input, ype and ypo is defiend as */
- /* YPeven= 3/2 x YPodd (line 1 = odd)" */
- /* */
- /* It looks like the spec is wrong! */
- /* The ad hoc values below works fine for a target */
- /* window height of 480 (vertical scale = 1/1) NTSC. */
- /* PLI: December 27, 2000. */
- ypo=64;
- ype=0;
- } else {
- ype = ysci / 16;
- ypo = ype + (ysci / 64);
- }
- }
- else {
- yacm = 1;
-
- /* calculate scaling increment */
- ysci = (((10 * 1024 * (in_y - out_y - 1)) / in_y) + 9) / 10;
-
- /* calculate ype and ypo */
- ypo = ype = ((ysci + 15) / 16);
-
- /* the sequence length interval (yacl) has to be set according
- to the prescale value, e.g. [n .. 1/2) : 0
- [1/2 .. 1/3) : 1
- [1/3 .. 1/4) : 2
- ... */
- if ( ysci < 512) {
- yacl = 0;
- }
- else {
- yacl = ( ysci / (1024 - ysci) );
- }
-
- /* get filter coefficients for cya, cyb from table hps_v_coeff_tab */
- cya_cyb = hps_v_coeff_tab[TRUNC(yacl, 63)].hps_coeff;
-
- /* get best match in the table of attenuations for vertical scaling */
- v_atten = hps_v_coeff_tab[TRUNC(yacl, 63)].weight_sum;
-
- for (i = 0; v_attenuation[i] != 0; i++) {
- if (v_attenuation[i] >= v_atten)
- break;
- }
-
- dcgy = i;
- }
-
- /* ypo and ype swapped in spec ? */
- *hps_v_scale |= (yacm << 31) | (ysci << 21) | (yacl << 15) | (ypo << 8 ) | (ype << 1);
-
- *hps_v_gain &= ~(MASK_W0|MASK_B2);
- *hps_v_gain |= (dcgy << 16) | (cya_cyb << 0);
-
- return 0;
-}
-
-void calculate_hxo_hyo_and_sources(struct saa7146* saa, int port_sel, int sync_sel, u32* hps_h_scale, u32* hps_ctrl)
-{
- u32 hyo = 0, hxo = 0;
-
- hyo = modes_constants[saa->mode].v_offset;
- hxo = modes_constants[saa->mode].h_offset;
-
- *hps_h_scale &= ~(MASK_B0 | 0xf00);
- *hps_ctrl &= ~(MASK_W0 | MASK_B2 | MASK_30 | MASK_31 | MASK_28);
-
- *hps_h_scale |= (hxo << 0);
- *hps_ctrl |= (hyo << 12);
-
- *hps_ctrl |= ( port_sel == 0 ? 0x0 : MASK_30);
- *hps_ctrl |= ( sync_sel == 0 ? 0x0 : MASK_28);
-}
-
-void calculate_output_format_register(struct saa7146* saa, u16 palette, u32* clip_format)
-{
- /* clear out the necessary bits */
- *clip_format &= 0x0000ffff;
- /* set these bits new */
- *clip_format |= (( ((palette&0xf00)>>8) << 30) | ((palette&0x00f) << 24) | (((palette&0x0f0)>>4) << 16));
-}
-
-void calculate_bcs_ctrl_register(struct saa7146 *saa, u32 brightness, u32 contrast, u32 colour, u32 *bcs_ctrl)
-{
- *bcs_ctrl = ((brightness << 24) | (contrast << 16) | (colour << 0));
-}
-
-
-int calculate_video_dma1_grab(struct saa7146* saa, int frame, struct saa7146_video_dma* vdma1)
-{
- int depth = 0;
-
- switch(saa->grab_format[frame]) {
- case YUV422_COMPOSED:
- case RGB15_COMPOSED:
- case RGB16_COMPOSED:
- depth = 2;
- break;
- case RGB24_COMPOSED:
- depth = 3;
- break;
- default:
- depth = 4;
- break;
- }
-
- vdma1->pitch = saa->grab_width[frame]*depth*2;
- vdma1->base_even = 0;
- vdma1->base_odd = vdma1->base_even + (vdma1->pitch/2);
- vdma1->prot_addr = (saa->grab_width[frame]*saa->grab_height[frame]*depth)-1;
- vdma1->num_line_byte = ((modes_constants[saa->mode].v_field<<16) + modes_constants[saa->mode].h_pixels);
- vdma1->base_page = virt_to_bus(saa->page_table[frame]) | ME1;
-
- /* convention: if scaling is between 1/2 and 1/4 we only use
- the even lines, the odd lines get discarded (see vertical scaling) */
- if( saa->interlace != 0 && saa->grab_height[frame]*4 >= modes_constants[saa->mode].v_calc && saa->grab_height[frame]*2 <= modes_constants[saa->mode].v_calc) {
- vdma1->base_odd = vdma1->prot_addr;
- vdma1->pitch /= 2;
- }
-
- return 0;
-}
-
-/* ---------------------------------------------*/
-/* position of overlay-window */
-/* ---------------------------------------------*/
-
-/* calculate the new memory offsets for a desired position */
-int move_to(struct saa7146* saa, int w_x, int w_y, int w_height, int b_width, int b_depth, int b_bpl, u32 base, int td_flip)
-{
- struct saa7146_video_dma vdma1;
-
- if( w_y < 0 || w_height <= 0 || b_depth <= 0 || b_bpl <= 0 || base == 0 ) {
- printk("saa7146: ==> calculate_video_dma1_overlay: illegal values: y: %d h: %d d: %d b: %d base: %d\n",w_y ,w_height,b_depth,b_bpl,base);
- return -EINVAL;
- }
-
- /* calculate memory offsets for picture, look if we shall top-down-flip */
- vdma1.pitch = 2*b_bpl;
- if ( 0 == td_flip ) {
- vdma1.prot_addr = (u32)base + ((w_height+w_y+1)*b_width*(b_depth/4));
- vdma1.base_even = (u32)base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
- vdma1.base_odd = vdma1.base_even + (vdma1.pitch / 2);
- }
- else {
- vdma1.prot_addr = (u32)base + (w_y * (vdma1.pitch/2));
- vdma1.base_even = (u32)base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
- vdma1.base_odd = vdma1.base_even + (vdma1.pitch / 2);
- vdma1.pitch *= -1;
- }
-
- /* convention: if scaling is between 1/2 and 1/4 we only use
- the even lines, the odd lines get discarded (see vertical scaling) */
- if( saa->interlace != 0 && w_height*4 >= modes_constants[saa->mode].v_calc && w_height*2 <= modes_constants[saa->mode].v_calc) {
- vdma1.base_odd = vdma1.prot_addr;
- vdma1.pitch /= 2;
- }
-
- vdma1.base_page = 0;
- vdma1.num_line_byte = (modes_constants[saa->mode].v_field<<16)+modes_constants[saa->mode].h_pixels;
-
- saa7146_write(saa->mem, BASE_EVEN1, vdma1.base_even);
- saa7146_write(saa->mem, BASE_ODD1, vdma1.base_odd);
- saa7146_write(saa->mem, PROT_ADDR1, vdma1.prot_addr);
- saa7146_write(saa->mem, BASE_PAGE1, vdma1.base_page);
- saa7146_write(saa->mem, PITCH1, vdma1.pitch);
- saa7146_write(saa->mem, NUM_LINE_BYTE1, vdma1.num_line_byte);
-
- /* update the video dma 1 registers */
- saa7146_write(saa->mem, MC2, (MASK_02 | MASK_18));
-
- return 0;
-
-}
-
-/* ---------------------------------------------*/
-/* size of window (overlay) */
-/* ---------------------------------------------*/
-
-int set_window(struct saa7146* saa, int width, int height, int flip_lr, int port_sel, int sync_sel)
-{
- u32 hps_v_scale = 0, hps_v_gain = 0, hps_ctrl = 0, hps_h_prescale = 0, hps_h_scale = 0;
-
- /* set vertical scale according to selected mode: 0 = PAL, 1 = NTSC */
- hps_v_scale = 0; /* all bits get set by the function-call */
- hps_v_gain = 0; /* fixme: saa7146_read(saa->mem, HPS_V_GAIN);*/
- calculate_v_scale_registers(saa, modes_constants[saa->mode].v_calc, height, &hps_v_scale, &hps_v_gain);
-
- /* set horizontal scale according to selected mode: 0 = PAL, 1 = NTSC */
- hps_ctrl = 0;
- hps_h_prescale = 0; /* all bits get set in the function */
- hps_h_scale = 0;
- calculate_h_scale_registers(saa, modes_constants[saa->mode].h_calc, width, 0, &hps_ctrl, &hps_v_gain, &hps_h_prescale, &hps_h_scale);
-
- /* set hyo and hxo */
- calculate_hxo_hyo_and_sources(saa, port_sel, sync_sel, &hps_h_scale, &hps_ctrl);
-
- /* write out new register contents */
- saa7146_write(saa->mem, HPS_V_SCALE, hps_v_scale);
- saa7146_write(saa->mem, HPS_V_GAIN, hps_v_gain);
- saa7146_write(saa->mem, HPS_CTRL, hps_ctrl);
- saa7146_write(saa->mem, HPS_H_PRESCALE,hps_h_prescale);
- saa7146_write(saa->mem, HPS_H_SCALE, hps_h_scale);
-
- /* upload shadow-ram registers */
- saa7146_write( saa->mem, MC2, (MASK_05 | MASK_06 | MASK_21 | MASK_22) );
-
-/*
- printk("w:%d,h:%d\n",width,height);
-*/
- return 0;
-
-}
-
-void set_output_format(struct saa7146* saa, u16 palette)
-{
- u32 clip_format = saa7146_read(saa->mem, CLIP_FORMAT_CTRL);
-
- dprintk("saa7146: ==> set_output_format: pal:0x%03x\n",palette);
-
- /* call helper function */
- calculate_output_format_register(saa,palette,&clip_format);
- dprintk("saa7146: ==> set_output_format: 0x%08x\n",clip_format);
-
- /* update the hps registers */
- saa7146_write(saa->mem, CLIP_FORMAT_CTRL, clip_format);
- saa7146_write(saa->mem, MC2, (MASK_05 | MASK_21));
-}
-
-void set_picture_prop(struct saa7146 *saa, u32 brightness, u32 contrast, u32 colour)
-{
- u32 bcs_ctrl = 0;
-
- calculate_bcs_ctrl_register(saa, brightness, contrast, colour, &bcs_ctrl);
- saa7146_write(saa->mem, BCS_CTRL, bcs_ctrl);
-
- /* update the bcs register */
- saa7146_write(saa->mem, MC2, (MASK_06 | MASK_22));
-}
-
-/* ---------------------------------------------*/
-/* overlay enable/disable */
-/* ---------------------------------------------*/
-
-/* enable(1) / disable(0) video */
-void video_setmode(struct saa7146* saa, int v)
-{
- hprintk("saa7146: ==> video_setmode; m:%d\n",v);
-
- /* disable ? */
- if(v==0) {
- /* disable video dma1 */
- saa7146_write(saa->mem, MC1, MASK_22);
- } else {/* or enable ? */
- /* fixme: enable video */
- saa7146_write(saa->mem, MC1, (MASK_06 | MASK_22));
- }
-}
-
-/* -----------------------------------------------------
- common grabbing-functions. if you have some simple
- saa7146-based frame-grabber you can most likely call
- these. they do all the revision-dependend stuff and
- do rps/irq-based grabbing for you.
- -----------------------------------------------------*/
-
-/* this function initializes the rps for the next grab for any "old"
- saa7146s (= revision 0). it assumes that the rps is *not* running
- when it gets called. */
-int init_rps0_rev0(struct saa7146* saa, int frame, int irq_call)
-{
- struct saa7146_video_dma vdma1;
- u32 hps_v_scale = 0, hps_v_gain = 0, hps_ctrl = 0, hps_h_prescale = 0, hps_h_scale = 0;
- u32 clip_format = 0; /* this can be 0, since we don't do clipping */
- u32 bcs_ctrl = 0;
-
- int count = 0;
-
-/* these static values are used to remember the last "programming" of the rps.
- if the height, width and format of the grab has not changed (which is very likely
- when some streaming capture is done) the reprogramming overhead can be minimized */
-static int last_height = 0;
-static int last_width = 0;
-static int last_format = 0;
-static int last_port = 0;
-static int last_frame = -1;
-
- /* write the address of the rps-program */
- saa7146_write(saa->mem, RPS_ADDR0, virt_to_bus(&saa->rps0[ 0]));
-
- /* let's check if we can re-use something of the last grabbing process */
- if ( saa->grab_height[frame] != last_height
- || saa->grab_width[frame] != last_width
- || saa->grab_port[frame] != last_port
- || saa->grab_format[frame] != last_format ) {
-
- /* nope, we have to start from the beginning */
- calculate_video_dma1_grab(saa, frame, &vdma1);
- calculate_v_scale_registers(saa, modes_constants[saa->mode].v_calc, saa->grab_height[frame], &hps_v_scale, &hps_v_gain);
- calculate_h_scale_registers(saa, modes_constants[saa->mode].h_calc, saa->grab_width[frame], 0, &hps_ctrl, &hps_v_gain, &hps_h_prescale, &hps_h_scale);
- calculate_hxo_hyo_and_sources(saa, saa->grab_port[frame], saa->grab_port[frame], &hps_h_scale, &hps_ctrl);
- calculate_output_format_register(saa,saa->grab_format[frame],&clip_format);
- calculate_bcs_ctrl_register(saa, 0x80, 0x40, 0x40, &bcs_ctrl);
-
- count = 0;
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_WR_REG_MASK | (MC1/4)); /* turn off video-dma1 and dma2 (clipping)*/
- saa->rps0[ count++ ] = cpu_to_le32(MASK_06 | MASK_22 | MASK_05 | MASK_21); /* => mask */
- saa->rps0[ count++ ] = cpu_to_le32(MASK_22 | MASK_21); /* => values */
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_PAUSE | ( saa->grab_port[frame] == 0 ? MASK_12 : MASK_14)); /* wait for o_fid_a/b */
- saa->rps0[ count++ ] = cpu_to_le32(CMD_PAUSE | ( saa->grab_port[frame] == 0 ? MASK_11 : MASK_13)); /* wait for e_fid_a/b */
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_WR_REG | (6 << 8) | HPS_CTRL/4); /* upload hps-registers for next grab */
- saa->rps0[ count++ ] = cpu_to_le32(hps_ctrl);
- saa->rps0[ count++ ] = cpu_to_le32(hps_v_scale);
- saa->rps0[ count++ ] = cpu_to_le32(hps_v_gain);
- saa->rps0[ count++ ] = cpu_to_le32(hps_h_prescale);
- saa->rps0[ count++ ] = cpu_to_le32(hps_h_scale);
- saa->rps0[ count++ ] = cpu_to_le32(bcs_ctrl);
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_WR_REG | (1 << 8) | CLIP_FORMAT_CTRL/4);/* upload hps-registers for next grab */
- saa->rps0[ count++ ] = cpu_to_le32(clip_format);
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_UPLOAD | MASK_05 | MASK_06); /* upload hps1/2 */
-
- /* upload video-dma1 registers for next grab */
- saa->rps0[ count++ ] = cpu_to_le32(CMD_WR_REG | (6 << 8) | BASE_ODD1/4);
- saa->rps0[ count++ ] = cpu_to_le32(vdma1.base_odd);
- saa->rps0[ count++ ] = cpu_to_le32(vdma1.base_even);
- saa->rps0[ count++ ] = cpu_to_le32(vdma1.prot_addr);
- saa->rps0[ count++ ] = cpu_to_le32(vdma1.pitch);
- saa->rps0[ count++ ] = cpu_to_le32(vdma1.base_page);
- saa->rps0[ count++ ] = cpu_to_le32(vdma1.num_line_byte);
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_UPLOAD | MASK_02); /* upload video-dma1 */
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_WR_REG_MASK | (MC1/4)); /* turn on video-dma1 */
- saa->rps0[ count++ ] = cpu_to_le32(MASK_06 | MASK_22); /* => mask */
- saa->rps0[ count++ ] = cpu_to_le32(MASK_06 | MASK_22); /* => values */
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_WR_REG | (1 << 8) | (MC2/4)); /* Write MC2 */
- saa->rps0[ count++ ] = cpu_to_le32((1 << (27+frame)) | (1 << (11+frame)));
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_PAUSE | ( saa->grab_port[frame] == 0 ? MASK_12 : MASK_14)); /* wait for o_fid_a/b */
- saa->rps0[ count++ ] = cpu_to_le32(CMD_PAUSE | ( saa->grab_port[frame] == 0 ? MASK_11 : MASK_13)); /* wait for e_fid_a/b */
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_WR_REG_MASK | (MC1/4)); /* turn off video-dma1 */
- saa->rps0[ count++ ] = cpu_to_le32(MASK_06 | MASK_22); /* => mask */
- saa->rps0[ count++ ] = cpu_to_le32(MASK_22); /* => values */
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_INTERRUPT); /* generate interrupt */
- saa->rps0[ count++ ] = cpu_to_le32(CMD_STOP); /* stop processing */
- } else {
-
- /* the height, width, ... have not changed. check if the user wants to grab to
- another *buffer* */
- if( frame != last_frame ) {
-
- /* ok, we want to grab to another buffer, but with the same programming.
- it is sufficient to adjust the video_dma1-registers and the rps-signal stuff. */
- saa->rps0[ 20 ] = cpu_to_le32(virt_to_bus(saa->page_table[frame]) | ME1);
- saa->rps0[ 27 ] = cpu_to_le32((1 << (27+frame)) | (1 << (11+frame)));
-
- }
- }
-
- /* if we are called from within the irq-handler, the hps is at the beginning of a
- new frame. the rps does not need to wait the new frame, and so we tweak the
- starting address a little bit and so we can directly start grabbing again.
- note: for large video-sizes and slow computers this can cause jaggy pictures
- because the whole process is not in sync. perhaps one should be able to
- disable this. (please remember that this whole stuff only belongs to
- "old" saa7146s (= revision 0), newer saa7146s don´t have any hardware-bugs
- and capture works fine. (see below) */
- if( 1 == irq_call ) {
- saa7146_write(saa->mem, RPS_ADDR0, virt_to_bus(&saa->rps0[15]));
- }
-
- /* turn on rps */
- saa7146_write(saa->mem, MC1, (MASK_12 | MASK_28));
-
- /* store the values for the last grab */
- last_height = saa->grab_height[frame];
- last_width = saa->grab_width[frame];
- last_format = saa->grab_format[frame];
- last_port = saa->grab_port[frame];
- last_frame = frame;
-
- return 0;
-}
-
-int init_rps0_rev1(struct saa7146* saa, int frame) {
-
-static int old_width[SAA7146_MAX_BUF]; /* pixel width of grabs */
-static int old_height[SAA7146_MAX_BUF]; /* pixel height of grabs */
-static int old_format[SAA7146_MAX_BUF]; /* video format of grabs */
-static int old_port[SAA7146_MAX_BUF]; /* video port for grab */
-
-static int buf_stat[SAA7146_MAX_BUF];
-
- struct saa7146_video_dma vdma1;
- u32 hps_v_scale = 0, hps_v_gain = 0, hps_ctrl = 0, hps_h_prescale = 0, hps_h_scale = 0;
- u32 clip_format = 0; /* this can be 0, since we don't do clipping */
- u32 bcs_ctrl = 0;
-
- int i = 0, count = 0;
-
- /* check if something has changed since the last grab for this buffer */
- if ( saa->grab_height[frame] == old_height[frame]
- && saa->grab_width[frame] == old_width[frame]
- && saa->grab_port[frame] == old_port[frame]
- && saa->grab_format[frame] == old_format[frame] ) {
-
- /* nope, nothing to be done here */
- return 0;
- }
-
- /* re-program the rps0 completely */
-
- /* indicate that the user has requested re-programming of the 'frame'-buffer */
- buf_stat[frame] = 1;
-
- /* turn off rps */
- saa7146_write(saa->mem, MC1, MASK_28);
-
-
- /* write beginning of rps-program */
- count = 0;
- saa->rps0[ count++ ] = cpu_to_le32(CMD_PAUSE | MASK_12); /* wait for o_fid_a */
- saa->rps0[ count++ ] = cpu_to_le32(CMD_PAUSE | MASK_11); /* wait for e_fid_a */
- for(i = 0; i < saa->buffers; i++) {
- saa->rps0[ count++ ] = cpu_to_le32(CMD_JUMP | (1 << (21+i))); /* check signal x, jump if set */
- saa->rps0[ count++ ] = cpu_to_le32(virt_to_bus(&saa->rps0[40*(i+1)]));
- }
- saa->rps0[ count++ ] = cpu_to_le32(CMD_PAUSE | MASK_12); /* wait for o_fid_a */
- saa->rps0[ count++ ] = cpu_to_le32(CMD_PAUSE | MASK_11); /* wait for e_fid_a */
- saa->rps0[ count++ ] = cpu_to_le32(CMD_JUMP); /* jump to the beginning */
- saa->rps0[ count++ ] = cpu_to_le32(virt_to_bus(&saa->rps0[2]));
-
- for(i = 0; i < saa->buffers; i++) {
-
- /* we only re-program the i-th buffer if the user had set some values for it earlier.
- otherwise the calculation-functions may fail. */
- if( buf_stat[i] == 0)
- continue;
-
- count = 40*(i+1);
-
- calculate_video_dma1_grab(saa, i, &vdma1);
- calculate_v_scale_registers(saa, modes_constants[saa->mode].v_calc, saa->grab_height[i], &hps_v_scale, &hps_v_gain);
- calculate_h_scale_registers(saa, modes_constants[saa->mode].h_calc, saa->grab_width[i], 0, &hps_ctrl, &hps_v_gain, &hps_h_prescale, &hps_h_scale);
- calculate_hxo_hyo_and_sources(saa, saa->grab_port[i], saa->grab_port[i], &hps_h_scale, &hps_ctrl);
- calculate_output_format_register(saa,saa->grab_format[i],&clip_format);
- calculate_bcs_ctrl_register(saa, 0x80, 0x40, 0x40, &bcs_ctrl);
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_WR_REG | (6 << 8) | HPS_CTRL/4); /* upload hps-registers for next grab */
- saa->rps0[ count++ ] = cpu_to_le32(hps_ctrl);
- saa->rps0[ count++ ] = cpu_to_le32(hps_v_scale);
- saa->rps0[ count++ ] = cpu_to_le32(hps_v_gain);
- saa->rps0[ count++ ] = cpu_to_le32(hps_h_prescale);
- saa->rps0[ count++ ] = cpu_to_le32(hps_h_scale);
- saa->rps0[ count++ ] = cpu_to_le32(bcs_ctrl);
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_WR_REG | (1 << 8) | CLIP_FORMAT_CTRL/4);/* upload hps-registers for next grab */
- saa->rps0[ count++ ] = cpu_to_le32(clip_format);
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_UPLOAD | MASK_05 | MASK_06); /* upload hps1/2 */
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_WR_REG | (6 << 8) | BASE_ODD1/4); /* upload video-dma1 registers for next grab */
- saa->rps0[ count++ ] = cpu_to_le32(vdma1.base_odd);
- saa->rps0[ count++ ] = cpu_to_le32(vdma1.base_even);
- saa->rps0[ count++ ] = cpu_to_le32(vdma1.prot_addr);
- saa->rps0[ count++ ] = cpu_to_le32(vdma1.pitch);
- saa->rps0[ count++ ] = cpu_to_le32(vdma1.base_page);
- saa->rps0[ count++ ] = cpu_to_le32(vdma1.num_line_byte);
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_UPLOAD | MASK_02); /* upload video-dma1 */
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_WR_REG_MASK | (MC1/4)); /* turn on video-dma1 */
- saa->rps0[ count++ ] = cpu_to_le32(MASK_06 | MASK_22); /* => mask */
- saa->rps0[ count++ ] = cpu_to_le32(MASK_06 | MASK_22); /* => values */
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_PAUSE | ( saa->grab_port[i] == 0 ? MASK_12 : MASK_14)); /* wait for o_fid_a/b */
- saa->rps0[ count++ ] = cpu_to_le32(CMD_PAUSE | ( saa->grab_port[i] == 0 ? MASK_11 : MASK_13)); /* wait for e_fid_a/b */
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_WR_REG_MASK | (MC1/4)); /* turn off video-dma1 and dma2 (clipping)*/
- saa->rps0[ count++ ] = cpu_to_le32(MASK_06 | MASK_22 | MASK_05 | MASK_21); /* => mask */
- saa->rps0[ count++ ] = cpu_to_le32(MASK_22 | MASK_21); /* => values */
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_WR_REG | (1 << 8) | (MC2/4)); /* Write MC2 */
- saa->rps0[ count++ ] = cpu_to_le32((1 << (27+i)));
- saa->rps0[ count++ ] = cpu_to_le32(CMD_INTERRUPT); /* generate interrupt */
-
- saa->rps0[ count++ ] = cpu_to_le32(CMD_JUMP); /* jump to the beginning */
- saa->rps0[ count++ ] = cpu_to_le32(virt_to_bus(&saa->rps0[2]));
-
- old_height[frame] = saa->grab_height[frame];
- old_width[frame] = saa->grab_width[frame];
- old_port[frame] = saa->grab_port[frame];
- old_format[frame] = saa->grab_format[frame];
- }
-
- /* write the address of the rps-program */
- saa7146_write(saa->mem, RPS_ADDR0, virt_to_bus(&saa->rps0[ 0]));
- /* turn on rps again */
- saa7146_write(saa->mem, MC1, (MASK_12 | MASK_28));
-
- return 0;
-}
-
-/* this funtion is called whenever a new grab is requested. if possible (that
- means: if the rps is not running) it re-programs the rps, otherwise it relys on
- the irq-handler to do that */
-int set_up_grabbing(struct saa7146* saa, int frame)
-{
- u32 mc1 = 0;
-
- if( 0 == saa->revision ) {
-
- /* check if the rps is currently in use */
- mc1 = saa7146_read(saa->mem, MC1);
-
- /* the rps is not running ... */
- if( 0 == ( mc1 & MASK_12) ) {
-
- /* we can completly re-program the rps now */
- dprintk("saa7146_v4l.o: ==> set_up_grabbing: start new rps.\n");
- init_rps0_rev0(saa,frame,0);
- } else {
-
- /* the rps is running. in this case, the irq-handler is responsible for
- re-programming the rps and nothing can be done right now */
- dprintk("saa7146_v4l.o: ==> set_up_grabbing: no new rps started.\n");
- }
- } else {
- /* check if something has changed, reprogram if necessary */
- init_rps0_rev1(saa,frame);
- /* set rps-signal-bit to start grabbing */
- saa7146_write(saa->mem, MC2, (1 << (27+frame)) | (1 << (11+frame)));
- }
-
- return 0;
-}
-
-
-void saa7146_std_grab_irq_callback_rps0(struct saa7146* saa, u32 isr, void* data)
-{
- u32 mc2 = 0;
- int i = 0;
-
- hprintk("saa7146_v4l.o: ==> saa7146_v4l_irq_callback_rps0\n");
-
- /* check for revision: old revision */
- if( 0 == saa->revision ) {
-
- /* look what buffer has been grabbed, set the ´done´-flag and clear the signal */
- mc2 = saa7146_read(saa->mem, MC2);
- for( i = 0; i < saa->buffers; i++ ) {
-
- if ((0 != (mc2 & (1 << (11+i)))) && (GBUFFER_GRABBING == saa->frame_stat[i])) {
- saa->frame_stat[i] = GBUFFER_DONE;
- saa7146_write(saa->mem, MC2, (1<<(27+i)));
- }
- }
-
- /* look if there is another buffer we can grab to */
- for( i = 0; i < saa->buffers; i++ ) {
- if ( GBUFFER_GRABBING == saa->frame_stat[i] )
- break;
- }
-
- /* yes, then set up the rps again */
- if( saa->buffers != i) {
- init_rps0_rev0(saa,i,1);
- }
- } else {
- /* new revisions */
-
- /* look what buffer has been grabbed, set the ´done´-flag */
- mc2 = saa7146_read(saa->mem, MC2);
- for( i = 0; i < saa->buffers; i++ ) {
-
- if ((0 == (mc2 & (1 << (11+i)))) && (GBUFFER_GRABBING == saa->frame_stat[i])) {
- saa->frame_stat[i] = GBUFFER_DONE;
- }
- }
-
- }
- /* notify any pending process */
- wake_up_interruptible(&saa->rps0_wq);
- return;
-}
-
-/* ---------------------------------------------*/
-/* mask-clipping */
-/* ---------------------------------------------*/
-int calculate_clipping_registers_mask(struct saa7146* saa, u32 width, u32 height, struct saa7146_video_dma* vdma2, u32* clip_format, u32* arbtr_ctrl)
-{
- u32 clip_addr = 0, clip_pitch = 0;
-
- dprintk("saa7146: ==> calculate_clipping_registers_mask\n");
-
- /* adjust arbitration control register */
- *arbtr_ctrl &= 0xffff00ff;
- *arbtr_ctrl |= 0x00001000;
-
- clip_addr = virt_to_bus(saa->clipping);
- clip_pitch = ((width+31)/32)*4;
-
- vdma2->base_even = clip_addr;
- vdma2->base_page = 0x04; /* enable read - operation */
- vdma2->prot_addr = clip_addr + (clip_pitch*height);
-
- /* convention: if scaling is between 1/2 and 1/4 we only use
- the even lines, the odd lines get discarded (see vertical scaling) */
- if( saa->interlace != 0 && height*4 >= modes_constants[saa->mode].v_calc && height*2 <= modes_constants[saa->mode].v_calc) {
- vdma2->base_odd = vdma2->prot_addr;
- vdma2->pitch = clip_pitch;
- vdma2->num_line_byte = (((height)-1) << 16) | (clip_pitch-1);
- } else {
- vdma2->base_odd = clip_addr+clip_pitch;
- vdma2->pitch = clip_pitch*2;
- vdma2->num_line_byte = (((height/2)-1) << 16) | (clip_pitch-1);
- }
-
- *clip_format &= 0xfffffff7;
-
- return 0;
-}
-
-/* helper functions for emulate rect-clipping via mask-clipping.
- note: these are extremely inefficient, but for clipping with less than 16
- windows rect-clipping should be done anyway...
-*/
-
-/* clear one pixel of the clipping memory at position (x,y) */
-void set_pixel(s32 x, s32 y, s32 window_width, u32* mem) {
-
- u32 mem_per_row = 0;
- u32 adr = 0;
- u32 shift = 0;
- u32 bit = 0;
-
- mem_per_row = (window_width + 31 )/ 32 ;
- adr = y * mem_per_row + (x / 32);
- shift = 31 - (x % 32);
- bit = (1 << shift);
-
- mem[adr] |= bit;
-}
-
-/* clear a box out of the clipping memory, beginning at (x,y) with "width" and "height" */
-void set_box(s32 x, s32 y, s32 width, s32 height, s32 window_width, s32 window_height, u32* mem)
-{
- s32 ty = 0;
- s32 tx = 0;
-
- /* the video_clip-struct may contain negative values to indicate that a window
- doesn't lay completly over the video window. Thus, we correct the values */
-
- if( width < 0) {
- x += width; width = -width;
- }
- if( height < 0) {
- y += height; height = -height;
- }
-
- if( x < 0) {
- width += x; x = 0;
- }
- if( y < 0) {
- height += y; y = 0;
- }
-
- if( width <= 0 || height <= 0) {
- printk("saa7146: ==> set_box: sanity error!\n");
- return;
- }
-
- if(x + width > window_width)
- width -= (x + width) - window_width;
- if(y + height > window_height)
- height -= (y + height) - window_height;
-
- /* Now, set a '1' in the memory, where no video picture should appear */
- for(ty = y; ty < y+height; ty++) {
- for(tx = x; tx < x+width; tx++) {
- set_pixel(tx, ty, window_width, mem);
- }
- }
-}
-
-int emulate_rect_clipping(struct saa7146 *saa, u16 clipcount, int x[], int y[], int w[], int h[], u32 w_width, u32 w_height)
-{
- int i = 0;
-
- /* clear out clipping mem */
- memset(saa->clipping, 0x0, CLIPPING_MEM_SIZE*sizeof(u32));
-
- /* go through list of clipping-windows, clear out rectangular-regions in the clipping memory */
- for(i = 0; i < clipcount; i++) {
- set_box(x[i], y[i], w[i], h[i], w_width, w_height, saa->clipping);
- }
-
- return 0;
-}
-
-/* ---------------------------------------------*/
-/* rectangle-clipping */
-/* ---------------------------------------------*/
-
-#define MIN(x,y) ( ((x) < (y)) ? (x) : (y) )
-#define MAX(x,y) ( ((x) > (y)) ? (x) : (y) )
-
-/* simple double-sort algorithm with duplicate elimination */
-int sort_and_eliminate(u32* values, int* count)
-{
- int low = 0, high = 0, top = 0, temp = 0;
- int cur = 0, next = 0;
-
- /* sanity checks */
- if( (0 > *count) || (NULL == values) ) {
- printk("saa7146: ==> sort_and_eliminate: internal error #1\n");
- return -EINVAL;
- }
-
- /* bubble sort the first ´count´ items of the array ´values´ */
- for( top = *count; top > 0; top--) {
- for( low = 0, high = 1; high < top; low++, high++) {
- if( values[low] > values[high] ) {
- temp = values[low];
- values[low] = values[high];
- values[high] = temp;
- }
- }
- }
-
- /* remove duplicate items */
- for( cur = 0, next = 1; next < *count; next++) {
- if( values[cur] != values[next])
- values[++cur] = values[next];
- }
-
- *count = cur + 1;
-
- return 0;
-}
-
-int calculate_clipping_registers_rect(struct saa7146 *saa, int clipcount, int x[], int y[], int w[], int h[], u32 width, u32 height, struct saa7146_video_dma* vdma2, u32* clip_format, u32* arbtr_ctrl)
-{
- u32 line_list[32];
- u32 pixel_list[32];
- u32 numdwords = 0;
-
- int i = 0, j = 0;
- int l = 0, r = 0, t = 0, b = 0;
- int cnt_line = 0, cnt_pixel = 0;
-
- dprintk("saa7146: ==> calculate_clipping_registers_clip\n");
-
- /* clear out memory */
- memset(&line_list[0], 0x00, sizeof(u32)*32);
- memset(&pixel_list[0], 0x00, sizeof(u32)*32);
- memset(saa->clipping, 0x00, sizeof(u32)*CLIPPING_MEM_SIZE);
-
- /* fill the line and pixel-lists */
- for(i = 0; i < clipcount; i++) {
-
- /* calculate values for l(eft), r(ight), t(op), b(ottom) */
- l = x[i];
- r = x[i]+w[i];
- t = y[i];
- b = y[i]+h[i];
-
- /* insert left/right coordinates */
- pixel_list[ 2*i ] = MIN(l, width);
- pixel_list[(2*i)+1] = MIN(r, width);
- /* insert top/bottom coordinates */
- line_list[ 2*i ] = MIN(t, height);
- line_list[(2*i)+1] = MIN(b, height);
- }
-
- /* sort and eliminate lists */
- cnt_line = cnt_pixel = 2*clipcount;
- sort_and_eliminate( &pixel_list[0], &cnt_pixel );
- sort_and_eliminate( &line_list[0], &cnt_line );
-
- /* calculate the number of used u32s */
- numdwords = MAX( (cnt_line+1), (cnt_pixel+1))*2;
- numdwords = MAX(4, numdwords);
- numdwords = MIN(64, numdwords);
-
- /* fill up cliptable */
- for(i = 0; i < cnt_pixel; i++) {
- saa->clipping[2*i] |= (pixel_list[i] << 16);
- }
- for(i = 0; i < cnt_line; i++) {
- saa->clipping[(2*i)+1] |= (line_list[i] << 16);
- }
-
- /* fill up cliptable with the display infos */
- for(j = 0; j < clipcount; j++) {
-
- for(i = 0; i < cnt_pixel; i++) {
-
- if( x[j] < 0)
- x[j] = 0;
-
- if( pixel_list[i] < (x[j] + w[j])) {
-
- if ( pixel_list[i] >= x[j] ) {
- saa->clipping[2*i] |= (1 << j);
- }
- }
- }
- for(i = 0; i < cnt_line; i++) {
-
- if( y[j] < 0)
- y[j] = 0;
-
- if( line_list[i] < (y[j] + h[j]) ) {
-
- if( line_list[i] >= y[j] ) {
- saa->clipping[(2*i)+1] |= (1 << j);
- }
- }
- }
- }
-
- /* adjust arbitration control register */
- *arbtr_ctrl &= 0xffff00ff;
- *arbtr_ctrl |= 0x00001c00;
-
- vdma2->base_even = virt_to_bus(saa->clipping);
- vdma2->base_odd = virt_to_bus(saa->clipping);
- vdma2->prot_addr = virt_to_bus(saa->clipping)+((sizeof(u32))*(numdwords));
- vdma2->base_page = 0x04;
- vdma2->pitch = 0x00;
- vdma2->num_line_byte = (0 << 16 | (sizeof(u32))*(numdwords-1) );
-
- /* set clipping-mode. please note again, that for sizes below 1/2, we only use the
- even-field. because of this, we have to specify ´recinterl´ correctly (specs, p. 97)*/
- *clip_format &= 0xfffffff7;
-
- if( saa->interlace != 0 && height*4 >= modes_constants[saa->mode].v_calc && height*2 <= modes_constants[saa->mode].v_calc) {
- *clip_format |= 0x00000000;
- } else {
- *clip_format |= 0x00000008;
- }
- return 0;
-}
-
-
-/* ---------------------------------------------*/
-/* main function for clipping */
-/* ---------------------------------------------*/
-/* arguments:
- type = see ´saa7146.h´
- width = width of the video-window
- height = height of the video-window
- *mask = pointer to mask memory (only needed for mask-clipping)
- *clips = pointer to clip-window-list (only needed for rect-clipping)
- clipcount = # of clip-windows (only needed for rect-clipping)
-*/
-int clip_windows(struct saa7146* saa, u32 type, u32 width, u32 height, u32* mask, u16 clipcount, int x[], int y[], int w[], int h[])
-{
- struct saa7146_video_dma vdma2;
-
- u32 clip_format = saa7146_read(saa->mem, CLIP_FORMAT_CTRL);
- u32 arbtr_ctrl = saa7146_read(saa->mem, PCI_BT_V1);
-
- hprintk("saa7146: ==> clip_windows\n");
-
- /* some sanity checks first */
- if ( width <= 0 || height <= 0 ) {
- printk("saa7146: ==> clip_windows: sanity error #1!\n");
- return -EINVAL;
- }
-
- /* check if anything to do here, disable clipping if == 0 */
- if( clipcount == 0 ) {
-
- /* mask out relevant bits (=lower word)*/
- clip_format &= MASK_W1;
-
- /* upload clipping-registers*/
- saa7146_write(saa->mem, CLIP_FORMAT_CTRL,clip_format);
- saa7146_write(saa->mem, MC2, (MASK_05 | MASK_21));
-
- /* disable video dma2 */
- saa7146_write(saa->mem, MC1, (MASK_21));
-
- return 0;
- }
-
- switch(type) {
-
- case SAA7146_CLIPPING_MASK_INVERTED:
- case SAA7146_CLIPPING_MASK:
- {
- printk("mask\n");
- /* sanity check */
- if( NULL == mask ) {
- printk("saa7146: ==> clip_windows: sanity error #1!\n");
- return -EINVAL;
- }
-
- /* copy the clipping mask to structure */
- memmove(saa->clipping, mask, CLIPPING_MEM_SIZE*sizeof(u32));
- /* set clipping registers */
- calculate_clipping_registers_mask(saa,width,height,&vdma2,&clip_format,&arbtr_ctrl);
-
- break;
- }
-
- case SAA7146_CLIPPING_RECT_INVERTED:
- case SAA7146_CLIPPING_RECT:
- {
- /* see if we have anything to do */
- if ( 0 == clipcount ) {
- return 0;
- }
-
- /* sanity check */
- if( NULL == x || NULL == y || NULL == w || NULL == h ) {
- printk("saa7146: ==> clip_windows: sanity error #2!\n");
- return -EINVAL;
- }
-
- /* rectangle clipping can only handle 16 overlay windows; if we
- have more, we have do emulate the whole thing with mask-clipping */
- if (1) { //clipcount > > 16 ) {
- //printk("emulate\n");
- emulate_rect_clipping(saa, clipcount, x,y,w,h, width, height);
- calculate_clipping_registers_mask(saa,width,height,&vdma2,&clip_format,&arbtr_ctrl);
- if( SAA7146_CLIPPING_RECT == type )
- type = SAA7146_CLIPPING_MASK;
- else
- type = SAA7146_CLIPPING_MASK_INVERTED;
-
- }
- else {
- calculate_clipping_registers_rect(saa,clipcount,x,y,w,h,width,height,&vdma2,&clip_format,&arbtr_ctrl);
- }
-
- break;
- }
-
- default:
- {
- printk("saa7146: ==> clip_windows: internal error #1!\n");
- return -EINVAL;
- }
-
- }
-
- /* set clipping format */
- clip_format &= 0xffff0008;
- clip_format |= (type << 4);
-
- saa7146_write(saa->mem, BASE_EVEN2, vdma2.base_even);
- saa7146_write(saa->mem, BASE_ODD2, vdma2.base_odd);
- saa7146_write(saa->mem, PROT_ADDR2, vdma2.prot_addr);
- saa7146_write(saa->mem, BASE_PAGE2, vdma2.base_page);
- saa7146_write(saa->mem, PITCH2, vdma2.pitch);
- saa7146_write(saa->mem, NUM_LINE_BYTE2, vdma2.num_line_byte);
-
- saa7146_write(saa->mem, CLIP_FORMAT_CTRL,clip_format);
- saa7146_write(saa->mem, PCI_BT_V1, arbtr_ctrl);
-
- /* upload clip_control-register, clipping-registers, enable video dma2 */
- saa7146_write(saa->mem, MC2, (MASK_05 | MASK_21 | MASK_03 | MASK_19));
- saa7146_write(saa->mem, MC1, (MASK_05 | MASK_21));
-/*
- printk("ARBTR_CTRL: 0x%08x\n",saa7146_read(saa->mem, PCI_BT_V1));
- printk("CLIP_FORMAT: 0x%08x\n",saa7146_read(saa->mem, CLIP_FORMAT_CTRL));
- printk("BASE_ODD1: 0x%08x\n",saa7146_read(saa->mem, BASE_ODD1));
- printk("BASE_EVEN1: 0x%08x\n",saa7146_read(saa->mem, BASE_EVEN1));
- printk("PROT_ADDR1: 0x%08x\n",saa7146_read(saa->mem, PROT_ADDR1));
- printk("PITCH1: 0x%08x\n",saa7146_read(saa->mem, PITCH1));
- printk("BASE_PAGE1: 0x%08x\n",saa7146_read(saa->mem, BASE_PAGE1));
- printk("NUM_LINE_BYTE1: 0x%08x\n",saa7146_read(saa->mem, NUM_LINE_BYTE1));
- printk("BASE_ODD2: 0x%08x\n",saa7146_read(saa->mem, BASE_ODD2));
- printk("BASE_EVEN2: 0x%08x\n",saa7146_read(saa->mem, BASE_EVEN2));
- printk("PROT_ADDR2: 0x%08x\n",saa7146_read(saa->mem, PROT_ADDR2));
- printk("PITCH2: 0x%08x\n",saa7146_read(saa->mem, PITCH2));
- printk("BASE_PAGE2: 0x%08x\n",saa7146_read(saa->mem, BASE_PAGE2));
- printk("NUM_LINE_BYTE2: 0x%08x\n",saa7146_read(saa->mem, NUM_LINE_BYTE2));
-*/
- return 0;
-
-}
-#endif
-
-#ifdef __COMPILE_SAA7146_I2C__
-
-/* ---------------------------------------------*/
-/* i2c-helper functions */
-/* ---------------------------------------------*/
-
-/* this functions gets the status from the saa7146 at address 'addr'
- and returns it */
-u32 i2c_status_check(struct saa7146* saa)
-{
- u32 iicsta = 0;
-
- iicsta = saa7146_read(saa->mem, I2C_STATUS );
- hprintk("saa7146: ==> i2c_status_check:0x%08x\n",iicsta);
-
- return iicsta;
-}
-
-/* this function should be called after an i2c-command has been written.
- if we are debugging, it checks, if the busy flags rises and falls correctly
- and reports a timeout (-1) or the error-bits set like in described in the specs,
- p.123, table 110 */
-int i2c_busy_rise_and_fall(struct saa7146* saa, int timeout)
-{
- int i = 0;
- u32 status = 0;
-
- hprintk("saa7146: ==> i2c_busy_rise_and_fall\n");
-
- /* wait until busy-flag rises */
- for (i = 5; i > 0; i--) {
-
- hprintk("saa7146: i2c_busy_rise_and_fall; rise wait %d\n",i);
-
- status = i2c_status_check(saa);
-
- /* check busy flag */
- if ( 0 != (status & SAA7146_I2C_BUSY))
- break;
-
- /* see if anything can be done while we're waiting */
- cond_resched ();
- mdelay(1);
- }
-
- /* we don't check the i-value, since it does not matter
- if we missed the rise of the busy flag or the fall or
- whatever. we just have to wait some undefined time
- after an i2c-command has been written out */
-
- /* wait until busy-flag is inactive or error is reported */
- for (i = timeout; i > 0; i--) {
-
- hprintk("saa7146: i2c_busy_rise_and_fall; fall wait %d\n",i);
-
- status = i2c_status_check(saa);
-
- /* check busy flag */
- if ( 0 == (status & SAA7146_I2C_BUSY))
- break;
-
- /* check error flag */
- if ( 0 != (status & SAA7146_I2C_ERR))
- break;
-
- /* see if anything can be done while we're waiting */
- cond_resched ();
-
- mdelay(1);
- }
-
- /* did a timeout occur ? */
- if ( 0 == i ) {
- hprintk("saa7146: i2c_busy_rise_and_fall: timeout #2\n");
- return -1;
- }
-
- /* report every error pending */
- switch( status & 0xfc ) {
-
- case SAA7146_I2C_SPERR:
- hprintk("saa7146: i2c_busy_rise_and_fall: error due to invalid start/stop condition\n");
- break;
-
- case SAA7146_I2C_APERR:
- hprintk("saa7146: i2c_busy_rise_and_fall: error in address phase\n");
- break;
-
- case SAA7146_I2C_DTERR:
- hprintk("saa7146: i2c_busy_rise_and_fall: error in data transmission\n");
- break;
-
- case SAA7146_I2C_DRERR:
- hprintk("saa7146: i2c_busy_rise_and_fall: error when receiving data\n");
- break;
-
- case SAA7146_I2C_AL:
- hprintk("saa7146: i2c_busy_rise_and_fall: error because arbitration lost\n");
- break;
- }
-
- return status;
-
-}
-
-/* this functions resets the saa7146 at address 'addr'
- and returns 0 if everything was fine, otherwise -1 */
-int i2c_reset(struct saa7146* saa)
-{
- u32 status = 0;
-
- hprintk("saa7146: ==> i2c_reset\n");
-
- status = i2c_status_check(saa);
-
- /* clear data-byte for sure */
- saa7146_write(saa->mem, I2C_TRANSFER, 0x00);
-
- /* check if any operation is still in progress */
- if ( 0 != ( status & SAA7146_I2C_BUSY) ) {
-
- /* Yes, kill ongoing operation */
- hprintk("saa7146: i2c_reset: busy_state detected\n");
-
- /* set ABORT-OPERATION-bit */
- saa7146_write(saa->mem, I2C_STATUS, ( SAA7146_I2C_BBR | MASK_07));
- saa7146_write(saa->mem, MC2, (MASK_00 | MASK_16));
- mdelay( SAA7146_I2C_DELAY );
-
- /* clear all error-bits pending; this is needed because p.123, note 1 */
- saa7146_write(saa->mem, I2C_STATUS, SAA7146_I2C_BBR );
- saa7146_write(saa->mem, MC2, (MASK_00 | MASK_16));
- mdelay( SAA7146_I2C_DELAY );
- }
-
- /* check if any other error is still present */
- if ( SAA7146_I2C_BBR != (status = i2c_status_check(saa)) ) {
-
- /* yes, try to kick it */
- hprintk("saa7146: i2c_reset: error_state detected, status:0x%08x\n",status);
-
- /* clear all error-bits pending */
- saa7146_write(saa->mem, I2C_STATUS, SAA7146_I2C_BBR );
- saa7146_write(saa->mem, MC2, (MASK_00 | MASK_16));
- mdelay( SAA7146_I2C_DELAY );
- /* the data sheet says it might be necessary to clear the status
- twice after an abort */
- saa7146_write(saa->mem, I2C_STATUS, SAA7146_I2C_BBR );
- saa7146_write(saa->mem, MC2, (MASK_00 | MASK_16));
- }
-
- /* if any error is still present, a fatal error has occured ... */
- if ( SAA7146_I2C_BBR != (status = i2c_status_check(saa)) ) {
- hprintk("saa7146: i2c_reset: fatal error, status:0x%08x\n",status);
- return -EIO;
- }
-
- return 0;
-}
-
-/* this functions writes out the data-bytes at 'data' to the saa7146
- at address 'addr' regarding the 'timeout' and 'retries' values;
- it returns 0 if ok, -1 if the transfer failed, -2 if the transfer
- failed badly (e.g. address error) */
-int i2c_write_out(struct saa7146* saa, u32* data, int timeout)
-{
- int status = 0;
-
- hprintk("saa7146: ==> writeout: 0x%08x (before) (to:%d)\n",*data,timeout);
-
- /* write out i2c-command */
- saa7146_write(saa->mem, I2C_TRANSFER, *data);
- saa7146_write(saa->mem, I2C_STATUS, SAA7146_I2C_BBR);
- saa7146_write(saa->mem, MC2, (MASK_00 | MASK_16));
-
- /* after writing out an i2c-command we have to wait for a while;
- because we do not know, how long we have to wait, we simply look
- what the busy-flag is doing, before doing something else */
-
- /* reason: while fiddling around with the i2c-routines, I noticed
- that after writing out an i2c-command, one may not read out the
- status immediately after that. you *must* wait some time, before
- even the busy-flag gets set */
-
- status = i2c_busy_rise_and_fall(saa,timeout);
-
- if ( -1 == status ) {
- hprintk("saa7146: i2c_write_out; timeout\n");
- return -ETIMEDOUT;
- }
-
- /* we only handle address-errors here */
- if ( 0 != (status & SAA7146_I2C_APERR)) {
- hprintk("saa7146: i2c_write_out; error in address phase\n");
- return -EREMOTEIO;
- }
-
- /* check for some other mysterious error; we don't handle this here */
- if ( 0 != ( status & 0xff)) {
- hprintk("saa7146: i2c_write_out: some error has occured\n");
- return -EIO;
- }
-
- /* read back data, just in case we were reading ... */
- *data = saa7146_read(saa->mem, I2C_TRANSFER);
-
- hprintk("saa7146: writeout: 0x%08x (after)\n",*data);
-
- return 0;
-}
-
-int clean_up(const struct i2c_msg *m, int num, u32 *op)
-{
- u16 i, j;
- u16 op_count = 0;
-
- /* loop through all messages */
- for(i = 0; i < num; i++) {
- op_count++;
- /* loop throgh all bytes of message i */
- for(j = 0; j < m[i].len; j++) {
- /* write back all bytes that could have been read */
- m[i].buf[j] = (op[op_count/3] >> ((3-(op_count%3))*8));
- op_count++;
- }
- }
-
- return 0;
-}
-
-int prepare(const struct i2c_msg *m, int num, u32 *op)
-{
- u16 h1, h2;
- u16 i, j, addr;
- u16 mem = 0, op_count = 0;
-
-//for (i=0; i<num; i++) { printk ("\n%02x (%s): ", m[i].addr, m[i].flags & I2C_M_RD ? "R" : "W"); for (j=0; j<m[i].len; j++) { m[i].buf[j] &= 0xff; printk (" %02x ", (u8) m[i].buf[j]); } } printk ("\n");
- /* determine size of needed memory */
- for(i = 0; i < num; i++)
- mem += m[i].len + 1;
-
- /* we need one u32 for three bytes to be send plus
- one byte to address the device */
- mem = 1 + ((mem-1) / 3);
-
- if ( mem > I2C_MEM_SIZE ) {
- hprintk("saa7146: prepare: i2c-message to big\n");
- return -1;
- }
-
- /* be careful: clear out the i2c-mem first */
- memset(op,0,sizeof(u32)*mem);
-
- for(i = 0; i < num; i++) {
- /* insert the address of the i2c-slave.
- * note: we get 7-bit-i2c-addresses,
- * so we have to perform a translation
- */
- addr = (m[i].addr << 1) | ((m[i].flags & I2C_M_RD) ? 1 : 0);
- h1 = op_count/3; h2 = op_count%3;
- op[h1] |= ((u8)addr << ((3-h2)*8));
- op[h1] |= (SAA7146_I2C_START << ((3-h2)*2));
- op_count++;
- /* loop through all bytes of message i */
- for(j = 0; j < m[i].len; j++) {
- /* insert the data bytes */
- h1 = op_count/3; h2 = op_count%3;
- op[h1] |= ((u8)m[i].buf[j] << ((3-h2)*8));
- op[h1] |= (SAA7146_I2C_CONT << ((3-h2)*2));
- op_count++;
- }
- }
-
- /* have a look at the last byte inserted:
- * if it was: ...CONT change it to ...STOP
- */
- h1 = (op_count-1)/3; h2 = (op_count-1)%3;
- if ( SAA7146_I2C_CONT == (0x3 & ((op[h1]) >> ((3-h2)*2))) ) {
- op[h1] &= ~(0x2 << ((3-h2)*2));
- op[h1] |= (SAA7146_I2C_STOP << ((3-h2)*2));
- }
-
- return mem;
-}
-#endif
-
-
-#ifdef __COMPILE_SAA7146_DEBI__
-
-/* functions for accessing the debi-port. note: we currently don't support
- * page-table-transfers.
- */
-
-#define MY_DEBI_TIMEOUT_MS 5
-
-int debi_transfer(struct saa7146* saa, struct saa7146_debi_transfer* dt)
-{
- u32 debi_config = 0, debi_command = 0, debi_page = 0, debi_ad = 0;
- u32 timeout = MY_DEBI_TIMEOUT_MS;
-
- /* sanity checks */
- if(dt->direction > 1 || dt->timeout > 15 || dt->swap > 3 || dt->slave16 > 2 || dt->intel > 1 || dt->increment > 1 || dt->tien > 1 )
- return -EINVAL;
-
- debi_page = 0;
- /* keep bits 31,30,28 clear */
- debi_config = (dt->timeout << 22) | (dt->swap << 20) | (dt->slave16 << 19) | (dt->increment << 18) | (dt->intel << 17) | (dt->tien << 16);
- debi_command = (dt->num_bytes << 17) | (dt->direction << 16) | (dt->address << 0);
- debi_ad = dt->mem;
-
- saa7146_write(saa->mem, DEBI_PAGE, debi_page);
- saa7146_write(saa->mem, DEBI_CONFIG, debi_config);
- saa7146_write(saa->mem, DEBI_COMMAND, debi_command);
- saa7146_write(saa->mem, DEBI_AD, debi_ad);
-
- /* upload debi-registers */
- saa7146_write(saa->mem, MC2, (MASK_01|MASK_17));
-
- /* wait for DEBI upload to complete */
- while (! (saa7146_read(saa->mem, MC2) & 0x2));
-
- while( --timeout ) {
- /* check, if DEBI still active */
- u32 psr = saa7146_read(saa->mem, PSR);
- if (0 != (psr & SPCI_DEBI_S)) {
- /* check, if error occured */
-/* if ( 0 != (saa7146_read(saa->mem, SSR) & (MASK_23|MASK_22))) { */
- if ( 0 != (saa7146_read(saa->mem, SSR) & (MASK_22))) {
- /* clear error status and indicate error */
- saa7146_write(saa->mem, ISR, SPCI_DEBI_E);
- return -1;
- }
- }
- else {
- /* Clear status bit */
- saa7146_write(saa->mem, ISR, SPCI_DEBI_S);
- break;
- }
- /* I don´t know how we should actually wait for the debi to have finished.
- we simply wait 1ms here and then check in a loop for max. MY_DEBI_TIMEOUT_MS */
- mdelay(1);
- }
-
- /* check for timeout */
- if( 0 == timeout ) {
- return -1;
- }
-
- /* read back data if we did immediate read-transfer */
- if(dt->num_bytes <= 4 && dt->direction == 1) {
- dt->mem = saa7146_read(saa->mem, DEBI_AD);
- switch(dt->num_bytes) {
- case 1:
- dt->mem &= 0x000000ff;
- break;
- case 2:
- dt->mem &= 0x0000ffff;
- break;
- case 3:
- dt->mem &= 0x00ffffff;
- break;
- }
- }
-
- return 0;
-}
-#endif
-
-#ifdef __COMPILE_SAA7146_STUFF__
-/* ---------------------------------------------*/
-/* helper-function: set gpio-pins */
-/* ---------------------------------------------*/
-void gpio_set(struct saa7146* saa, u8 pin, u8 data)
-{
- u32 value = 0;
-
- /* sanity check */
- if(pin > 3)
- return;
-
- /* read old register contents */
- value = saa7146_read(saa->mem, GPIO_CTRL );
-
- value &= ~(0xff << (8*pin));
- value |= (data << (8*pin));
-
- saa7146_write(saa->mem, GPIO_CTRL, value);
-}
-
-void select_input(struct saa7146* saa, int p)
-{
- u32 hps_ctrl = 0;
-
- /* sanity check */
- if( p < 0 || p > 1 )
- return;
-
- /* read old state */
- hps_ctrl = saa7146_read(saa->mem, HPS_CTRL);
-
- /* mask out relevant bits */
- hps_ctrl &= ~( MASK_31 | MASK_30 | MASK_28 );
-
- /* set bits for input b */
- if( 1 == p ) {
- hps_ctrl |= ( (1 << 30) | (1 << 28) );
- }
-
- /* write back & upload register */
- saa7146_write(saa->mem, HPS_CTRL, hps_ctrl);
- saa7146_write(saa->mem, MC2, (MASK_05 | MASK_21));
-}
-
-#endif
-