diff options
Diffstat (limited to 'linux/drivers/media/dvb/av7110/saa7146.c')
-rw-r--r-- | linux/drivers/media/dvb/av7110/saa7146.c | 1662 |
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 - |