162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/kernel.h> 562306a36Sopenharmony_ci#include <linux/export.h> 662306a36Sopenharmony_ci#include <media/drv-intf/saa7146_vv.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_cistatic void calculate_output_format_register(struct saa7146_dev* saa, u32 palette, u32* clip_format) 962306a36Sopenharmony_ci{ 1062306a36Sopenharmony_ci /* clear out the necessary bits */ 1162306a36Sopenharmony_ci *clip_format &= 0x0000ffff; 1262306a36Sopenharmony_ci /* set these bits new */ 1362306a36Sopenharmony_ci *clip_format |= (( ((palette&0xf00)>>8) << 30) | ((palette&0x00f) << 24) | (((palette&0x0f0)>>4) << 16)); 1462306a36Sopenharmony_ci} 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic void calculate_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync, u32* hps_ctrl) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci *hps_ctrl &= ~(MASK_30 | MASK_31 | MASK_28); 1962306a36Sopenharmony_ci *hps_ctrl |= (source << 30) | (sync << 28); 2062306a36Sopenharmony_ci} 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic void calculate_hxo_and_hyo(struct saa7146_vv *vv, u32* hps_h_scale, u32* hps_ctrl) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci int hyo = 0, hxo = 0; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci hyo = vv->standard->v_offset; 2762306a36Sopenharmony_ci hxo = vv->standard->h_offset; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci *hps_h_scale &= ~(MASK_B0 | 0xf00); 3062306a36Sopenharmony_ci *hps_h_scale |= (hxo << 0); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci *hps_ctrl &= ~(MASK_W0 | MASK_B2); 3362306a36Sopenharmony_ci *hps_ctrl |= (hyo << 12); 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* helper functions for the calculation of the horizontal- and vertical 3762306a36Sopenharmony_ci scaling registers, clip-format-register etc ... 3862306a36Sopenharmony_ci these functions take pointers to the (most-likely read-out 3962306a36Sopenharmony_ci original-values) and manipulate them according to the requested 4062306a36Sopenharmony_ci changes. 4162306a36Sopenharmony_ci*/ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* hps_coeff used for CXY and CXUV; scale 1/1 -> scale 1/64 */ 4462306a36Sopenharmony_cistatic struct { 4562306a36Sopenharmony_ci u16 hps_coeff; 4662306a36Sopenharmony_ci u16 weight_sum; 4762306a36Sopenharmony_ci} hps_h_coeff_tab [] = { 4862306a36Sopenharmony_ci {0x00, 2}, {0x02, 4}, {0x00, 4}, {0x06, 8}, {0x02, 8}, 4962306a36Sopenharmony_ci {0x08, 8}, {0x00, 8}, {0x1E, 16}, {0x0E, 8}, {0x26, 8}, 5062306a36Sopenharmony_ci {0x06, 8}, {0x42, 8}, {0x02, 8}, {0x80, 8}, {0x00, 8}, 5162306a36Sopenharmony_ci {0xFE, 16}, {0xFE, 8}, {0x7E, 8}, {0x7E, 8}, {0x3E, 8}, 5262306a36Sopenharmony_ci {0x3E, 8}, {0x1E, 8}, {0x1E, 8}, {0x0E, 8}, {0x0E, 8}, 5362306a36Sopenharmony_ci {0x06, 8}, {0x06, 8}, {0x02, 8}, {0x02, 8}, {0x00, 8}, 5462306a36Sopenharmony_ci {0x00, 8}, {0xFE, 16}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, 5562306a36Sopenharmony_ci {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, 5662306a36Sopenharmony_ci {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, 5762306a36Sopenharmony_ci {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0xFE, 8}, {0x7E, 8}, 5862306a36Sopenharmony_ci {0x7E, 8}, {0x3E, 8}, {0x3E, 8}, {0x1E, 8}, {0x1E, 8}, 5962306a36Sopenharmony_ci {0x0E, 8}, {0x0E, 8}, {0x06, 8}, {0x06, 8}, {0x02, 8}, 6062306a36Sopenharmony_ci {0x02, 8}, {0x00, 8}, {0x00, 8}, {0xFE, 16} 6162306a36Sopenharmony_ci}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* table of attenuation values for horizontal scaling */ 6462306a36Sopenharmony_cistatic u8 h_attenuation[] = { 1, 2, 4, 8, 2, 4, 8, 16, 0}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/* calculate horizontal scale registers */ 6762306a36Sopenharmony_cistatic int calculate_h_scale_registers(struct saa7146_dev *dev, 6862306a36Sopenharmony_ci int in_x, int out_x, int flip_lr, 6962306a36Sopenharmony_ci u32* hps_ctrl, u32* hps_v_gain, u32* hps_h_prescale, u32* hps_h_scale) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci /* horizontal prescaler */ 7262306a36Sopenharmony_ci u32 dcgx = 0, xpsc = 0, xacm = 0, cxy = 0, cxuv = 0; 7362306a36Sopenharmony_ci /* horizontal scaler */ 7462306a36Sopenharmony_ci u32 xim = 0, xp = 0, xsci =0; 7562306a36Sopenharmony_ci /* vertical scale & gain */ 7662306a36Sopenharmony_ci u32 pfuv = 0; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci /* helper variables */ 7962306a36Sopenharmony_ci u32 h_atten = 0, i = 0; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if ( 0 == out_x ) { 8262306a36Sopenharmony_ci return -EINVAL; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* mask out vanity-bit */ 8662306a36Sopenharmony_ci *hps_ctrl &= ~MASK_29; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* calculate prescale-(xspc)-value: [n .. 1/2) : 1 8962306a36Sopenharmony_ci [1/2 .. 1/3) : 2 9062306a36Sopenharmony_ci [1/3 .. 1/4) : 3 9162306a36Sopenharmony_ci ... */ 9262306a36Sopenharmony_ci if (in_x > out_x) { 9362306a36Sopenharmony_ci xpsc = in_x / out_x; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci else { 9662306a36Sopenharmony_ci /* zooming */ 9762306a36Sopenharmony_ci xpsc = 1; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci /* if flip_lr-bit is set, number of pixels after 10162306a36Sopenharmony_ci horizontal prescaling must be < 384 */ 10262306a36Sopenharmony_ci if ( 0 != flip_lr ) { 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci /* set vanity bit */ 10562306a36Sopenharmony_ci *hps_ctrl |= MASK_29; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci while (in_x / xpsc >= 384 ) 10862306a36Sopenharmony_ci xpsc++; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci /* if zooming is wanted, number of pixels after 11162306a36Sopenharmony_ci horizontal prescaling must be < 768 */ 11262306a36Sopenharmony_ci else { 11362306a36Sopenharmony_ci while ( in_x / xpsc >= 768 ) 11462306a36Sopenharmony_ci xpsc++; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci /* maximum prescale is 64 (p.69) */ 11862306a36Sopenharmony_ci if ( xpsc > 64 ) 11962306a36Sopenharmony_ci xpsc = 64; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* keep xacm clear*/ 12262306a36Sopenharmony_ci xacm = 0; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* set horizontal filter parameters (CXY = CXUV) */ 12562306a36Sopenharmony_ci cxy = hps_h_coeff_tab[( (xpsc - 1) < 63 ? (xpsc - 1) : 63 )].hps_coeff; 12662306a36Sopenharmony_ci cxuv = cxy; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* calculate and set horizontal fine scale (xsci) */ 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* bypass the horizontal scaler ? */ 13162306a36Sopenharmony_ci if ( (in_x == out_x) && ( 1 == xpsc ) ) 13262306a36Sopenharmony_ci xsci = 0x400; 13362306a36Sopenharmony_ci else 13462306a36Sopenharmony_ci xsci = ( (1024 * in_x) / (out_x * xpsc) ) + xpsc; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* set start phase for horizontal fine scale (xp) to 0 */ 13762306a36Sopenharmony_ci xp = 0; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci /* set xim, if we bypass the horizontal scaler */ 14062306a36Sopenharmony_ci if ( 0x400 == xsci ) 14162306a36Sopenharmony_ci xim = 1; 14262306a36Sopenharmony_ci else 14362306a36Sopenharmony_ci xim = 0; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* if the prescaler is bypassed, enable horizontal 14662306a36Sopenharmony_ci accumulation mode (xacm) and clear dcgx */ 14762306a36Sopenharmony_ci if( 1 == xpsc ) { 14862306a36Sopenharmony_ci xacm = 1; 14962306a36Sopenharmony_ci dcgx = 0; 15062306a36Sopenharmony_ci } else { 15162306a36Sopenharmony_ci xacm = 0; 15262306a36Sopenharmony_ci /* get best match in the table of attenuations 15362306a36Sopenharmony_ci for horizontal scaling */ 15462306a36Sopenharmony_ci h_atten = hps_h_coeff_tab[( (xpsc - 1) < 63 ? (xpsc - 1) : 63 )].weight_sum; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci for (i = 0; h_attenuation[i] != 0; i++) { 15762306a36Sopenharmony_ci if (h_attenuation[i] >= h_atten) 15862306a36Sopenharmony_ci break; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci dcgx = i; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* the horizontal scaling increment controls the UV filter 16562306a36Sopenharmony_ci to reduce the bandwidth to improve the display quality, 16662306a36Sopenharmony_ci so set it ... */ 16762306a36Sopenharmony_ci if ( xsci == 0x400) 16862306a36Sopenharmony_ci pfuv = 0x00; 16962306a36Sopenharmony_ci else if ( xsci < 0x600) 17062306a36Sopenharmony_ci pfuv = 0x01; 17162306a36Sopenharmony_ci else if ( xsci < 0x680) 17262306a36Sopenharmony_ci pfuv = 0x11; 17362306a36Sopenharmony_ci else if ( xsci < 0x700) 17462306a36Sopenharmony_ci pfuv = 0x22; 17562306a36Sopenharmony_ci else 17662306a36Sopenharmony_ci pfuv = 0x33; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci *hps_v_gain &= MASK_W0|MASK_B2; 18062306a36Sopenharmony_ci *hps_v_gain |= (pfuv << 24); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci *hps_h_scale &= ~(MASK_W1 | 0xf000); 18362306a36Sopenharmony_ci *hps_h_scale |= (xim << 31) | (xp << 24) | (xsci << 12); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci *hps_h_prescale |= (dcgx << 27) | ((xpsc-1) << 18) | (xacm << 17) | (cxy << 8) | (cxuv << 0); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci return 0; 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic struct { 19162306a36Sopenharmony_ci u16 hps_coeff; 19262306a36Sopenharmony_ci u16 weight_sum; 19362306a36Sopenharmony_ci} hps_v_coeff_tab [] = { 19462306a36Sopenharmony_ci {0x0100, 2}, {0x0102, 4}, {0x0300, 4}, {0x0106, 8}, {0x0502, 8}, 19562306a36Sopenharmony_ci {0x0708, 8}, {0x0F00, 8}, {0x011E, 16}, {0x110E, 16}, {0x1926, 16}, 19662306a36Sopenharmony_ci {0x3906, 16}, {0x3D42, 16}, {0x7D02, 16}, {0x7F80, 16}, {0xFF00, 16}, 19762306a36Sopenharmony_ci {0x01FE, 32}, {0x01FE, 32}, {0x817E, 32}, {0x817E, 32}, {0xC13E, 32}, 19862306a36Sopenharmony_ci {0xC13E, 32}, {0xE11E, 32}, {0xE11E, 32}, {0xF10E, 32}, {0xF10E, 32}, 19962306a36Sopenharmony_ci {0xF906, 32}, {0xF906, 32}, {0xFD02, 32}, {0xFD02, 32}, {0xFF00, 32}, 20062306a36Sopenharmony_ci {0xFF00, 32}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, 20162306a36Sopenharmony_ci {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, 20262306a36Sopenharmony_ci {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, 20362306a36Sopenharmony_ci {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x01FE, 64}, {0x817E, 64}, 20462306a36Sopenharmony_ci {0x817E, 64}, {0xC13E, 64}, {0xC13E, 64}, {0xE11E, 64}, {0xE11E, 64}, 20562306a36Sopenharmony_ci {0xF10E, 64}, {0xF10E, 64}, {0xF906, 64}, {0xF906, 64}, {0xFD02, 64}, 20662306a36Sopenharmony_ci {0xFD02, 64}, {0xFF00, 64}, {0xFF00, 64}, {0x01FE, 128} 20762306a36Sopenharmony_ci}; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci/* table of attenuation values for vertical scaling */ 21062306a36Sopenharmony_cistatic u16 v_attenuation[] = { 2, 4, 8, 16, 32, 64, 128, 256, 0}; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci/* calculate vertical scale registers */ 21362306a36Sopenharmony_cistatic int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field field, 21462306a36Sopenharmony_ci int in_y, int out_y, u32* hps_v_scale, u32* hps_v_gain) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci int lpi = 0; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci /* vertical scaling */ 21962306a36Sopenharmony_ci u32 yacm = 0, ysci = 0, yacl = 0, ypo = 0, ype = 0; 22062306a36Sopenharmony_ci /* vertical scale & gain */ 22162306a36Sopenharmony_ci u32 dcgy = 0, cya_cyb = 0; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* helper variables */ 22462306a36Sopenharmony_ci u32 v_atten = 0, i = 0; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* error, if vertical zooming */ 22762306a36Sopenharmony_ci if ( in_y < out_y ) { 22862306a36Sopenharmony_ci return -EINVAL; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci /* linear phase interpolation may be used 23262306a36Sopenharmony_ci if scaling is between 1 and 1/2 (both fields used) 23362306a36Sopenharmony_ci or scaling is between 1/2 and 1/4 (if only one field is used) */ 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci if (V4L2_FIELD_HAS_BOTH(field)) { 23662306a36Sopenharmony_ci if( 2*out_y >= in_y) { 23762306a36Sopenharmony_ci lpi = 1; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci } else if (field == V4L2_FIELD_TOP 24062306a36Sopenharmony_ci || field == V4L2_FIELD_ALTERNATE 24162306a36Sopenharmony_ci || field == V4L2_FIELD_BOTTOM) { 24262306a36Sopenharmony_ci if( 4*out_y >= in_y ) { 24362306a36Sopenharmony_ci lpi = 1; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci out_y *= 2; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci if( 0 != lpi ) { 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci yacm = 0; 25062306a36Sopenharmony_ci yacl = 0; 25162306a36Sopenharmony_ci cya_cyb = 0x00ff; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* calculate scaling increment */ 25462306a36Sopenharmony_ci if ( in_y > out_y ) 25562306a36Sopenharmony_ci ysci = ((1024 * in_y) / (out_y + 1)) - 1024; 25662306a36Sopenharmony_ci else 25762306a36Sopenharmony_ci ysci = 0; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci dcgy = 0; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* calculate ype and ypo */ 26262306a36Sopenharmony_ci ype = ysci / 16; 26362306a36Sopenharmony_ci ypo = ype + (ysci / 64); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci } else { 26662306a36Sopenharmony_ci yacm = 1; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci /* calculate scaling increment */ 26962306a36Sopenharmony_ci ysci = (((10 * 1024 * (in_y - out_y - 1)) / in_y) + 9) / 10; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* calculate ype and ypo */ 27262306a36Sopenharmony_ci ypo = ype = ((ysci + 15) / 16); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* the sequence length interval (yacl) has to be set according 27562306a36Sopenharmony_ci to the prescale value, e.g. [n .. 1/2) : 0 27662306a36Sopenharmony_ci [1/2 .. 1/3) : 1 27762306a36Sopenharmony_ci [1/3 .. 1/4) : 2 27862306a36Sopenharmony_ci ... */ 27962306a36Sopenharmony_ci if ( ysci < 512) { 28062306a36Sopenharmony_ci yacl = 0; 28162306a36Sopenharmony_ci } else { 28262306a36Sopenharmony_ci yacl = ( ysci / (1024 - ysci) ); 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci /* get filter coefficients for cya, cyb from table hps_v_coeff_tab */ 28662306a36Sopenharmony_ci cya_cyb = hps_v_coeff_tab[ (yacl < 63 ? yacl : 63 ) ].hps_coeff; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* get best match in the table of attenuations for vertical scaling */ 28962306a36Sopenharmony_ci v_atten = hps_v_coeff_tab[ (yacl < 63 ? yacl : 63 ) ].weight_sum; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci for (i = 0; v_attenuation[i] != 0; i++) { 29262306a36Sopenharmony_ci if (v_attenuation[i] >= v_atten) 29362306a36Sopenharmony_ci break; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci dcgy = i; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* ypo and ype swapped in spec ? */ 30062306a36Sopenharmony_ci *hps_v_scale |= (yacm << 31) | (ysci << 21) | (yacl << 15) | (ypo << 8 ) | (ype << 1); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci *hps_v_gain &= ~(MASK_W0|MASK_B2); 30362306a36Sopenharmony_ci *hps_v_gain |= (dcgy << 16) | (cya_cyb << 0); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci return 0; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci/* simple bubble-sort algorithm with duplicate elimination */ 30962306a36Sopenharmony_cistatic void saa7146_set_window(struct saa7146_dev *dev, int width, int height, enum v4l2_field field) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci struct saa7146_vv *vv = dev->vv_data; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci int source = vv->current_hps_source; 31462306a36Sopenharmony_ci int sync = vv->current_hps_sync; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci u32 hps_v_scale = 0, hps_v_gain = 0, hps_ctrl = 0, hps_h_prescale = 0, hps_h_scale = 0; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* set vertical scale */ 31962306a36Sopenharmony_ci hps_v_scale = 0; /* all bits get set by the function-call */ 32062306a36Sopenharmony_ci hps_v_gain = 0; /* fixme: saa7146_read(dev, HPS_V_GAIN);*/ 32162306a36Sopenharmony_ci calculate_v_scale_registers(dev, field, vv->standard->v_field*2, height, &hps_v_scale, &hps_v_gain); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* set horizontal scale */ 32462306a36Sopenharmony_ci hps_ctrl = 0; 32562306a36Sopenharmony_ci hps_h_prescale = 0; /* all bits get set in the function */ 32662306a36Sopenharmony_ci hps_h_scale = 0; 32762306a36Sopenharmony_ci calculate_h_scale_registers(dev, vv->standard->h_pixels, width, vv->hflip, &hps_ctrl, &hps_v_gain, &hps_h_prescale, &hps_h_scale); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci /* set hyo and hxo */ 33062306a36Sopenharmony_ci calculate_hxo_and_hyo(vv, &hps_h_scale, &hps_ctrl); 33162306a36Sopenharmony_ci calculate_hps_source_and_sync(dev, source, sync, &hps_ctrl); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* write out new register contents */ 33462306a36Sopenharmony_ci saa7146_write(dev, HPS_V_SCALE, hps_v_scale); 33562306a36Sopenharmony_ci saa7146_write(dev, HPS_V_GAIN, hps_v_gain); 33662306a36Sopenharmony_ci saa7146_write(dev, HPS_CTRL, hps_ctrl); 33762306a36Sopenharmony_ci saa7146_write(dev, HPS_H_PRESCALE,hps_h_prescale); 33862306a36Sopenharmony_ci saa7146_write(dev, HPS_H_SCALE, hps_h_scale); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci /* upload shadow-ram registers */ 34162306a36Sopenharmony_ci saa7146_write(dev, MC2, (MASK_05 | MASK_06 | MASK_21 | MASK_22) ); 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic void saa7146_set_output_format(struct saa7146_dev *dev, unsigned long palette) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci /* call helper function */ 34962306a36Sopenharmony_ci calculate_output_format_register(dev,palette,&clip_format); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* update the hps registers */ 35262306a36Sopenharmony_ci saa7146_write(dev, CLIP_FORMAT_CTRL, clip_format); 35362306a36Sopenharmony_ci saa7146_write(dev, MC2, (MASK_05 | MASK_21)); 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci/* select input-source */ 35762306a36Sopenharmony_civoid saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct saa7146_vv *vv = dev->vv_data; 36062306a36Sopenharmony_ci u32 hps_ctrl = 0; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci /* read old state */ 36362306a36Sopenharmony_ci hps_ctrl = saa7146_read(dev, HPS_CTRL); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci hps_ctrl &= ~( MASK_31 | MASK_30 | MASK_28 ); 36662306a36Sopenharmony_ci hps_ctrl |= (source << 30) | (sync << 28); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* write back & upload register */ 36962306a36Sopenharmony_ci saa7146_write(dev, HPS_CTRL, hps_ctrl); 37062306a36Sopenharmony_ci saa7146_write(dev, MC2, (MASK_05 | MASK_21)); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci vv->current_hps_source = source; 37362306a36Sopenharmony_ci vv->current_hps_sync = sync; 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_civoid saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci int where = 0; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if( which < 1 || which > 3) { 38262306a36Sopenharmony_ci return; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* calculate starting address */ 38662306a36Sopenharmony_ci where = (which-1)*0x18; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci saa7146_write(dev, where, vdma->base_odd); 38962306a36Sopenharmony_ci saa7146_write(dev, where+0x04, vdma->base_even); 39062306a36Sopenharmony_ci saa7146_write(dev, where+0x08, vdma->prot_addr); 39162306a36Sopenharmony_ci saa7146_write(dev, where+0x0c, vdma->pitch); 39262306a36Sopenharmony_ci saa7146_write(dev, where+0x10, vdma->base_page); 39362306a36Sopenharmony_ci saa7146_write(dev, where+0x14, vdma->num_line_byte); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci /* upload */ 39662306a36Sopenharmony_ci saa7146_write(dev, MC2, (MASK_02<<(which-1))|(MASK_18<<(which-1))); 39762306a36Sopenharmony_ci/* 39862306a36Sopenharmony_ci printk("vdma%d.base_even: 0x%08x\n", which,vdma->base_even); 39962306a36Sopenharmony_ci printk("vdma%d.base_odd: 0x%08x\n", which,vdma->base_odd); 40062306a36Sopenharmony_ci printk("vdma%d.prot_addr: 0x%08x\n", which,vdma->prot_addr); 40162306a36Sopenharmony_ci printk("vdma%d.base_page: 0x%08x\n", which,vdma->base_page); 40262306a36Sopenharmony_ci printk("vdma%d.pitch: 0x%08x\n", which,vdma->pitch); 40362306a36Sopenharmony_ci printk("vdma%d.num_line_byte: 0x%08x\n", which,vdma->num_line_byte); 40462306a36Sopenharmony_ci*/ 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa7146_buf *buf) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct saa7146_vv *vv = dev->vv_data; 41062306a36Sopenharmony_ci struct v4l2_pix_format *pix = &vv->video_fmt; 41162306a36Sopenharmony_ci struct saa7146_video_dma vdma1; 41262306a36Sopenharmony_ci struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pix->pixelformat); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci int width = pix->width; 41562306a36Sopenharmony_ci int height = pix->height; 41662306a36Sopenharmony_ci int bytesperline = pix->bytesperline; 41762306a36Sopenharmony_ci enum v4l2_field field = pix->field; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci int depth = sfmt->depth; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci DEB_CAP("[size=%dx%d,fields=%s]\n", 42262306a36Sopenharmony_ci width, height, v4l2_field_names[field]); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci if( bytesperline != 0) { 42562306a36Sopenharmony_ci vdma1.pitch = bytesperline*2; 42662306a36Sopenharmony_ci } else { 42762306a36Sopenharmony_ci vdma1.pitch = (width*depth*2)/8; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci vdma1.num_line_byte = ((vv->standard->v_field<<16) + vv->standard->h_pixels); 43062306a36Sopenharmony_ci vdma1.base_page = buf->pt[0].dma | ME1 | sfmt->swap; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if( 0 != vv->vflip ) { 43362306a36Sopenharmony_ci vdma1.prot_addr = buf->pt[0].offset; 43462306a36Sopenharmony_ci vdma1.base_even = buf->pt[0].offset+(vdma1.pitch/2)*height; 43562306a36Sopenharmony_ci vdma1.base_odd = vdma1.base_even - (vdma1.pitch/2); 43662306a36Sopenharmony_ci } else { 43762306a36Sopenharmony_ci vdma1.base_even = buf->pt[0].offset; 43862306a36Sopenharmony_ci vdma1.base_odd = vdma1.base_even + (vdma1.pitch/2); 43962306a36Sopenharmony_ci vdma1.prot_addr = buf->pt[0].offset+(vdma1.pitch/2)*height; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (V4L2_FIELD_HAS_BOTH(field)) { 44362306a36Sopenharmony_ci } else if (field == V4L2_FIELD_ALTERNATE) { 44462306a36Sopenharmony_ci /* fixme */ 44562306a36Sopenharmony_ci if ( vv->last_field == V4L2_FIELD_TOP ) { 44662306a36Sopenharmony_ci vdma1.base_odd = vdma1.prot_addr; 44762306a36Sopenharmony_ci vdma1.pitch /= 2; 44862306a36Sopenharmony_ci } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) { 44962306a36Sopenharmony_ci vdma1.base_odd = vdma1.base_even; 45062306a36Sopenharmony_ci vdma1.base_even = vdma1.prot_addr; 45162306a36Sopenharmony_ci vdma1.pitch /= 2; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci } else if (field == V4L2_FIELD_TOP) { 45462306a36Sopenharmony_ci vdma1.base_odd = vdma1.prot_addr; 45562306a36Sopenharmony_ci vdma1.pitch /= 2; 45662306a36Sopenharmony_ci } else if (field == V4L2_FIELD_BOTTOM) { 45762306a36Sopenharmony_ci vdma1.base_odd = vdma1.base_even; 45862306a36Sopenharmony_ci vdma1.base_even = vdma1.prot_addr; 45962306a36Sopenharmony_ci vdma1.pitch /= 2; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if( 0 != vv->vflip ) { 46362306a36Sopenharmony_ci vdma1.pitch *= -1; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci saa7146_write_out_dma(dev, 1, &vdma1); 46762306a36Sopenharmony_ci return 0; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic int calc_planar_422(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci struct v4l2_pix_format *pix = &vv->video_fmt; 47362306a36Sopenharmony_ci int height = pix->height; 47462306a36Sopenharmony_ci int width = pix->width; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci vdma2->pitch = width; 47762306a36Sopenharmony_ci vdma3->pitch = width; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* fixme: look at bytesperline! */ 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci if( 0 != vv->vflip ) { 48262306a36Sopenharmony_ci vdma2->prot_addr = buf->pt[1].offset; 48362306a36Sopenharmony_ci vdma2->base_even = ((vdma2->pitch/2)*height)+buf->pt[1].offset; 48462306a36Sopenharmony_ci vdma2->base_odd = vdma2->base_even - (vdma2->pitch/2); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci vdma3->prot_addr = buf->pt[2].offset; 48762306a36Sopenharmony_ci vdma3->base_even = ((vdma3->pitch/2)*height)+buf->pt[2].offset; 48862306a36Sopenharmony_ci vdma3->base_odd = vdma3->base_even - (vdma3->pitch/2); 48962306a36Sopenharmony_ci } else { 49062306a36Sopenharmony_ci vdma3->base_even = buf->pt[2].offset; 49162306a36Sopenharmony_ci vdma3->base_odd = vdma3->base_even + (vdma3->pitch/2); 49262306a36Sopenharmony_ci vdma3->prot_addr = (vdma3->pitch/2)*height+buf->pt[2].offset; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci vdma2->base_even = buf->pt[1].offset; 49562306a36Sopenharmony_ci vdma2->base_odd = vdma2->base_even + (vdma2->pitch/2); 49662306a36Sopenharmony_ci vdma2->prot_addr = (vdma2->pitch/2)*height+buf->pt[1].offset; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci return 0; 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic int calc_planar_420(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci struct v4l2_pix_format *pix = &vv->video_fmt; 50562306a36Sopenharmony_ci int height = pix->height; 50662306a36Sopenharmony_ci int width = pix->width; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci vdma2->pitch = width/2; 50962306a36Sopenharmony_ci vdma3->pitch = width/2; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if( 0 != vv->vflip ) { 51262306a36Sopenharmony_ci vdma2->prot_addr = buf->pt[2].offset; 51362306a36Sopenharmony_ci vdma2->base_even = ((vdma2->pitch/2)*height)+buf->pt[2].offset; 51462306a36Sopenharmony_ci vdma2->base_odd = vdma2->base_even - (vdma2->pitch/2); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci vdma3->prot_addr = buf->pt[1].offset; 51762306a36Sopenharmony_ci vdma3->base_even = ((vdma3->pitch/2)*height)+buf->pt[1].offset; 51862306a36Sopenharmony_ci vdma3->base_odd = vdma3->base_even - (vdma3->pitch/2); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci } else { 52162306a36Sopenharmony_ci vdma3->base_even = buf->pt[2].offset; 52262306a36Sopenharmony_ci vdma3->base_odd = vdma3->base_even + (vdma3->pitch); 52362306a36Sopenharmony_ci vdma3->prot_addr = (vdma3->pitch/2)*height+buf->pt[2].offset; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci vdma2->base_even = buf->pt[1].offset; 52662306a36Sopenharmony_ci vdma2->base_odd = vdma2->base_even + (vdma2->pitch); 52762306a36Sopenharmony_ci vdma2->prot_addr = (vdma2->pitch/2)*height+buf->pt[1].offset; 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci return 0; 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa7146_buf *buf) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci struct saa7146_vv *vv = dev->vv_data; 53562306a36Sopenharmony_ci struct v4l2_pix_format *pix = &vv->video_fmt; 53662306a36Sopenharmony_ci struct saa7146_video_dma vdma1; 53762306a36Sopenharmony_ci struct saa7146_video_dma vdma2; 53862306a36Sopenharmony_ci struct saa7146_video_dma vdma3; 53962306a36Sopenharmony_ci struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pix->pixelformat); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci int width = pix->width; 54262306a36Sopenharmony_ci int height = pix->height; 54362306a36Sopenharmony_ci enum v4l2_field field = pix->field; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (WARN_ON(!buf->pt[0].dma) || 54662306a36Sopenharmony_ci WARN_ON(!buf->pt[1].dma) || 54762306a36Sopenharmony_ci WARN_ON(!buf->pt[2].dma)) 54862306a36Sopenharmony_ci return -1; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci DEB_CAP("[size=%dx%d,fields=%s]\n", 55162306a36Sopenharmony_ci width, height, v4l2_field_names[field]); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci /* fixme: look at bytesperline! */ 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci /* fixme: what happens for user space buffers here?. The offsets are 55662306a36Sopenharmony_ci most likely wrong, this version here only works for page-aligned 55762306a36Sopenharmony_ci buffers, modifications to the pagetable-functions are necessary...*/ 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci vdma1.pitch = width*2; 56062306a36Sopenharmony_ci vdma1.num_line_byte = ((vv->standard->v_field<<16) + vv->standard->h_pixels); 56162306a36Sopenharmony_ci vdma1.base_page = buf->pt[0].dma | ME1; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if( 0 != vv->vflip ) { 56462306a36Sopenharmony_ci vdma1.prot_addr = buf->pt[0].offset; 56562306a36Sopenharmony_ci vdma1.base_even = ((vdma1.pitch/2)*height)+buf->pt[0].offset; 56662306a36Sopenharmony_ci vdma1.base_odd = vdma1.base_even - (vdma1.pitch/2); 56762306a36Sopenharmony_ci } else { 56862306a36Sopenharmony_ci vdma1.base_even = buf->pt[0].offset; 56962306a36Sopenharmony_ci vdma1.base_odd = vdma1.base_even + (vdma1.pitch/2); 57062306a36Sopenharmony_ci vdma1.prot_addr = (vdma1.pitch/2)*height+buf->pt[0].offset; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci vdma2.num_line_byte = 0; /* unused */ 57462306a36Sopenharmony_ci vdma2.base_page = buf->pt[1].dma | ME1; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci vdma3.num_line_byte = 0; /* unused */ 57762306a36Sopenharmony_ci vdma3.base_page = buf->pt[2].dma | ME1; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci switch( sfmt->depth ) { 58062306a36Sopenharmony_ci case 12: { 58162306a36Sopenharmony_ci calc_planar_420(vv,buf,&vdma2,&vdma3); 58262306a36Sopenharmony_ci break; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci case 16: { 58562306a36Sopenharmony_ci calc_planar_422(vv,buf,&vdma2,&vdma3); 58662306a36Sopenharmony_ci break; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci default: { 58962306a36Sopenharmony_ci return -1; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci if (V4L2_FIELD_HAS_BOTH(field)) { 59462306a36Sopenharmony_ci } else if (field == V4L2_FIELD_ALTERNATE) { 59562306a36Sopenharmony_ci /* fixme */ 59662306a36Sopenharmony_ci vdma1.base_odd = vdma1.prot_addr; 59762306a36Sopenharmony_ci vdma1.pitch /= 2; 59862306a36Sopenharmony_ci vdma2.base_odd = vdma2.prot_addr; 59962306a36Sopenharmony_ci vdma2.pitch /= 2; 60062306a36Sopenharmony_ci vdma3.base_odd = vdma3.prot_addr; 60162306a36Sopenharmony_ci vdma3.pitch /= 2; 60262306a36Sopenharmony_ci } else if (field == V4L2_FIELD_TOP) { 60362306a36Sopenharmony_ci vdma1.base_odd = vdma1.prot_addr; 60462306a36Sopenharmony_ci vdma1.pitch /= 2; 60562306a36Sopenharmony_ci vdma2.base_odd = vdma2.prot_addr; 60662306a36Sopenharmony_ci vdma2.pitch /= 2; 60762306a36Sopenharmony_ci vdma3.base_odd = vdma3.prot_addr; 60862306a36Sopenharmony_ci vdma3.pitch /= 2; 60962306a36Sopenharmony_ci } else if (field == V4L2_FIELD_BOTTOM) { 61062306a36Sopenharmony_ci vdma1.base_odd = vdma1.base_even; 61162306a36Sopenharmony_ci vdma1.base_even = vdma1.prot_addr; 61262306a36Sopenharmony_ci vdma1.pitch /= 2; 61362306a36Sopenharmony_ci vdma2.base_odd = vdma2.base_even; 61462306a36Sopenharmony_ci vdma2.base_even = vdma2.prot_addr; 61562306a36Sopenharmony_ci vdma2.pitch /= 2; 61662306a36Sopenharmony_ci vdma3.base_odd = vdma3.base_even; 61762306a36Sopenharmony_ci vdma3.base_even = vdma3.prot_addr; 61862306a36Sopenharmony_ci vdma3.pitch /= 2; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci if( 0 != vv->vflip ) { 62262306a36Sopenharmony_ci vdma1.pitch *= -1; 62362306a36Sopenharmony_ci vdma2.pitch *= -1; 62462306a36Sopenharmony_ci vdma3.pitch *= -1; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci saa7146_write_out_dma(dev, 1, &vdma1); 62862306a36Sopenharmony_ci if( (sfmt->flags & FORMAT_BYTE_SWAP) != 0 ) { 62962306a36Sopenharmony_ci saa7146_write_out_dma(dev, 3, &vdma2); 63062306a36Sopenharmony_ci saa7146_write_out_dma(dev, 2, &vdma3); 63162306a36Sopenharmony_ci } else { 63262306a36Sopenharmony_ci saa7146_write_out_dma(dev, 2, &vdma2); 63362306a36Sopenharmony_ci saa7146_write_out_dma(dev, 3, &vdma3); 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci return 0; 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic void program_capture_engine(struct saa7146_dev *dev, int planar) 63962306a36Sopenharmony_ci{ 64062306a36Sopenharmony_ci struct saa7146_vv *vv = dev->vv_data; 64162306a36Sopenharmony_ci int count = 0; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B; 64462306a36Sopenharmony_ci unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci /* wait for o_fid_a/b / e_fid_a/b toggle only if rps register 0 is not set*/ 64762306a36Sopenharmony_ci WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | o_wait); 64862306a36Sopenharmony_ci WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | e_wait); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci /* set rps register 0 */ 65162306a36Sopenharmony_ci WRITE_RPS0(CMD_WR_REG | (1 << 8) | (MC2/4)); 65262306a36Sopenharmony_ci WRITE_RPS0(MASK_27 | MASK_11); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci /* turn on video-dma1 */ 65562306a36Sopenharmony_ci WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); 65662306a36Sopenharmony_ci WRITE_RPS0(MASK_06 | MASK_22); /* => mask */ 65762306a36Sopenharmony_ci WRITE_RPS0(MASK_06 | MASK_22); /* => values */ 65862306a36Sopenharmony_ci if( 0 != planar ) { 65962306a36Sopenharmony_ci /* turn on video-dma2 */ 66062306a36Sopenharmony_ci WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); 66162306a36Sopenharmony_ci WRITE_RPS0(MASK_05 | MASK_21); /* => mask */ 66262306a36Sopenharmony_ci WRITE_RPS0(MASK_05 | MASK_21); /* => values */ 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci /* turn on video-dma3 */ 66562306a36Sopenharmony_ci WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); 66662306a36Sopenharmony_ci WRITE_RPS0(MASK_04 | MASK_20); /* => mask */ 66762306a36Sopenharmony_ci WRITE_RPS0(MASK_04 | MASK_20); /* => values */ 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* wait for o_fid_a/b / e_fid_a/b toggle */ 67162306a36Sopenharmony_ci if ( vv->last_field == V4L2_FIELD_INTERLACED ) { 67262306a36Sopenharmony_ci WRITE_RPS0(CMD_PAUSE | o_wait); 67362306a36Sopenharmony_ci WRITE_RPS0(CMD_PAUSE | e_wait); 67462306a36Sopenharmony_ci } else if ( vv->last_field == V4L2_FIELD_TOP ) { 67562306a36Sopenharmony_ci WRITE_RPS0(CMD_PAUSE | (vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? MASK_10 : MASK_09)); 67662306a36Sopenharmony_ci WRITE_RPS0(CMD_PAUSE | o_wait); 67762306a36Sopenharmony_ci } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) { 67862306a36Sopenharmony_ci WRITE_RPS0(CMD_PAUSE | (vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? MASK_10 : MASK_09)); 67962306a36Sopenharmony_ci WRITE_RPS0(CMD_PAUSE | e_wait); 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci /* turn off video-dma1 */ 68362306a36Sopenharmony_ci WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); 68462306a36Sopenharmony_ci WRITE_RPS0(MASK_22 | MASK_06); /* => mask */ 68562306a36Sopenharmony_ci WRITE_RPS0(MASK_22); /* => values */ 68662306a36Sopenharmony_ci if( 0 != planar ) { 68762306a36Sopenharmony_ci /* turn off video-dma2 */ 68862306a36Sopenharmony_ci WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); 68962306a36Sopenharmony_ci WRITE_RPS0(MASK_05 | MASK_21); /* => mask */ 69062306a36Sopenharmony_ci WRITE_RPS0(MASK_21); /* => values */ 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci /* turn off video-dma3 */ 69362306a36Sopenharmony_ci WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4)); 69462306a36Sopenharmony_ci WRITE_RPS0(MASK_04 | MASK_20); /* => mask */ 69562306a36Sopenharmony_ci WRITE_RPS0(MASK_20); /* => values */ 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci /* generate interrupt */ 69962306a36Sopenharmony_ci WRITE_RPS0(CMD_INTERRUPT); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci /* stop */ 70262306a36Sopenharmony_ci WRITE_RPS0(CMD_STOP); 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci/* disable clipping */ 70662306a36Sopenharmony_cistatic void saa7146_disable_clipping(struct saa7146_dev *dev) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* mask out relevant bits (=lower word)*/ 71162306a36Sopenharmony_ci clip_format &= MASK_W1; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci /* upload clipping-registers*/ 71462306a36Sopenharmony_ci saa7146_write(dev, CLIP_FORMAT_CTRL, clip_format); 71562306a36Sopenharmony_ci saa7146_write(dev, MC2, (MASK_05 | MASK_21)); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci /* disable video dma2 */ 71862306a36Sopenharmony_ci saa7146_write(dev, MC1, MASK_21); 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_civoid saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci struct saa7146_vv *vv = dev->vv_data; 72462306a36Sopenharmony_ci struct v4l2_pix_format *pix = &vv->video_fmt; 72562306a36Sopenharmony_ci struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pix->pixelformat); 72662306a36Sopenharmony_ci u32 vdma1_prot_addr; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci DEB_CAP("buf:%p, next:%p\n", buf, next); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci vdma1_prot_addr = saa7146_read(dev, PROT_ADDR1); 73162306a36Sopenharmony_ci if( 0 == vdma1_prot_addr ) { 73262306a36Sopenharmony_ci /* clear out beginning of streaming bit (rps register 0)*/ 73362306a36Sopenharmony_ci DEB_CAP("forcing sync to new frame\n"); 73462306a36Sopenharmony_ci saa7146_write(dev, MC2, MASK_27 ); 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci saa7146_set_window(dev, pix->width, pix->height, pix->field); 73862306a36Sopenharmony_ci saa7146_set_output_format(dev, sfmt->trans); 73962306a36Sopenharmony_ci saa7146_disable_clipping(dev); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci if ( vv->last_field == V4L2_FIELD_INTERLACED ) { 74262306a36Sopenharmony_ci } else if ( vv->last_field == V4L2_FIELD_TOP ) { 74362306a36Sopenharmony_ci vv->last_field = V4L2_FIELD_BOTTOM; 74462306a36Sopenharmony_ci } else if ( vv->last_field == V4L2_FIELD_BOTTOM ) { 74562306a36Sopenharmony_ci vv->last_field = V4L2_FIELD_TOP; 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if( 0 != IS_PLANAR(sfmt->trans)) { 74962306a36Sopenharmony_ci calculate_video_dma_grab_planar(dev, buf); 75062306a36Sopenharmony_ci program_capture_engine(dev,1); 75162306a36Sopenharmony_ci } else { 75262306a36Sopenharmony_ci calculate_video_dma_grab_packed(dev, buf); 75362306a36Sopenharmony_ci program_capture_engine(dev,0); 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci/* 75762306a36Sopenharmony_ci printk("vdma%d.base_even: 0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1)); 75862306a36Sopenharmony_ci printk("vdma%d.base_odd: 0x%08x\n", 1,saa7146_read(dev,BASE_ODD1)); 75962306a36Sopenharmony_ci printk("vdma%d.prot_addr: 0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1)); 76062306a36Sopenharmony_ci printk("vdma%d.base_page: 0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1)); 76162306a36Sopenharmony_ci printk("vdma%d.pitch: 0x%08x\n", 1,saa7146_read(dev,PITCH1)); 76262306a36Sopenharmony_ci printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1)); 76362306a36Sopenharmony_ci printk("vdma%d => vptr : 0x%08x\n", 1,saa7146_read(dev,PCI_VDP1)); 76462306a36Sopenharmony_ci*/ 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci /* write the address of the rps-program */ 76762306a36Sopenharmony_ci saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci /* turn on rps */ 77062306a36Sopenharmony_ci saa7146_write(dev, MC1, (MASK_12 | MASK_28)); 77162306a36Sopenharmony_ci} 772