cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

saa7146_hlp.c (30780B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      3
      4#include <linux/kernel.h>
      5#include <linux/export.h>
      6#include <media/drv-intf/saa7146_vv.h>
      7
      8static void calculate_output_format_register(struct saa7146_dev* saa, u32 palette, u32* clip_format)
      9{
     10	/* clear out the necessary bits */
     11	*clip_format &= 0x0000ffff;
     12	/* set these bits new */
     13	*clip_format |=  (( ((palette&0xf00)>>8) << 30) | ((palette&0x00f) << 24) | (((palette&0x0f0)>>4) << 16));
     14}
     15
     16static void calculate_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync, u32* hps_ctrl)
     17{
     18	*hps_ctrl &= ~(MASK_30 | MASK_31 | MASK_28);
     19	*hps_ctrl |= (source << 30) | (sync << 28);
     20}
     21
     22static void calculate_hxo_and_hyo(struct saa7146_vv *vv, u32* hps_h_scale, u32* hps_ctrl)
     23{
     24	int hyo = 0, hxo = 0;
     25
     26	hyo = vv->standard->v_offset;
     27	hxo = vv->standard->h_offset;
     28
     29	*hps_h_scale	&= ~(MASK_B0 | 0xf00);
     30	*hps_h_scale	|= (hxo <<  0);
     31
     32	*hps_ctrl	&= ~(MASK_W0 | MASK_B2);
     33	*hps_ctrl	|= (hyo << 12);
     34}
     35
     36/* helper functions for the calculation of the horizontal- and vertical
     37   scaling registers, clip-format-register etc ...
     38   these functions take pointers to the (most-likely read-out
     39   original-values) and manipulate them according to the requested
     40   changes.
     41*/
     42
     43/* hps_coeff used for CXY and CXUV; scale 1/1 -> scale 1/64 */
     44static struct {
     45	u16 hps_coeff;
     46	u16 weight_sum;
     47} hps_h_coeff_tab [] = {
     48	{0x00,   2}, {0x02,   4}, {0x00,   4}, {0x06,   8}, {0x02,   8},
     49	{0x08,   8}, {0x00,   8}, {0x1E,  16}, {0x0E,   8}, {0x26,   8},
     50	{0x06,   8}, {0x42,   8}, {0x02,   8}, {0x80,   8}, {0x00,   8},
     51	{0xFE,  16}, {0xFE,   8}, {0x7E,   8}, {0x7E,   8}, {0x3E,   8},
     52	{0x3E,   8}, {0x1E,   8}, {0x1E,   8}, {0x0E,   8}, {0x0E,   8},
     53	{0x06,   8}, {0x06,   8}, {0x02,   8}, {0x02,   8}, {0x00,   8},
     54	{0x00,   8}, {0xFE,  16}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8},
     55	{0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8},
     56	{0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8},
     57	{0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0xFE,   8}, {0x7E,   8},
     58	{0x7E,   8}, {0x3E,   8}, {0x3E,   8}, {0x1E,   8}, {0x1E,   8},
     59	{0x0E,   8}, {0x0E,   8}, {0x06,   8}, {0x06,   8}, {0x02,   8},
     60	{0x02,   8}, {0x00,   8}, {0x00,   8}, {0xFE,  16}
     61};
     62
     63/* table of attenuation values for horizontal scaling */
     64static u8 h_attenuation[] = { 1, 2, 4, 8, 2, 4, 8, 16, 0};
     65
     66/* calculate horizontal scale registers */
     67static int calculate_h_scale_registers(struct saa7146_dev *dev,
     68	int in_x, int out_x, int flip_lr,
     69	u32* hps_ctrl, u32* hps_v_gain, u32* hps_h_prescale, u32* hps_h_scale)
     70{
     71	/* horizontal prescaler */
     72	u32 dcgx = 0, xpsc = 0, xacm = 0, cxy = 0, cxuv = 0;
     73	/* horizontal scaler */
     74	u32 xim = 0, xp = 0, xsci =0;
     75	/* vertical scale & gain */
     76	u32 pfuv = 0;
     77
     78	/* helper variables */
     79	u32 h_atten = 0, i = 0;
     80
     81	if ( 0 == out_x ) {
     82		return -EINVAL;
     83	}
     84
     85	/* mask out vanity-bit */
     86	*hps_ctrl &= ~MASK_29;
     87
     88	/* calculate prescale-(xspc)-value:	[n   .. 1/2) : 1
     89						[1/2 .. 1/3) : 2
     90						[1/3 .. 1/4) : 3
     91						...		*/
     92	if (in_x > out_x) {
     93		xpsc = in_x / out_x;
     94	}
     95	else {
     96		/* zooming */
     97		xpsc = 1;
     98	}
     99
    100	/* if flip_lr-bit is set, number of pixels after
    101	   horizontal prescaling must be < 384 */
    102	if ( 0 != flip_lr ) {
    103
    104		/* set vanity bit */
    105		*hps_ctrl |= MASK_29;
    106
    107		while (in_x / xpsc >= 384 )
    108			xpsc++;
    109	}
    110	/* if zooming is wanted, number of pixels after
    111	   horizontal prescaling must be < 768 */
    112	else {
    113		while ( in_x / xpsc >= 768 )
    114			xpsc++;
    115	}
    116
    117	/* maximum prescale is 64 (p.69) */
    118	if ( xpsc > 64 )
    119		xpsc = 64;
    120
    121	/* keep xacm clear*/
    122	xacm = 0;
    123
    124	/* set horizontal filter parameters (CXY = CXUV) */
    125	cxy = hps_h_coeff_tab[( (xpsc - 1) < 63 ? (xpsc - 1) : 63 )].hps_coeff;
    126	cxuv = cxy;
    127
    128	/* calculate and set horizontal fine scale (xsci) */
    129
    130	/* bypass the horizontal scaler ? */
    131	if ( (in_x == out_x) && ( 1 == xpsc ) )
    132		xsci = 0x400;
    133	else
    134		xsci = ( (1024 * in_x) / (out_x * xpsc) ) + xpsc;
    135
    136	/* set start phase for horizontal fine scale (xp) to 0 */
    137	xp = 0;
    138
    139	/* set xim, if we bypass the horizontal scaler */
    140	if ( 0x400 == xsci )
    141		xim = 1;
    142	else
    143		xim = 0;
    144
    145	/* if the prescaler is bypassed, enable horizontal
    146	   accumulation mode (xacm) and clear dcgx */
    147	if( 1 == xpsc ) {
    148		xacm = 1;
    149		dcgx = 0;
    150	} else {
    151		xacm = 0;
    152		/* get best match in the table of attenuations
    153		   for horizontal scaling */
    154		h_atten = hps_h_coeff_tab[( (xpsc - 1) < 63 ? (xpsc - 1) : 63 )].weight_sum;
    155
    156		for (i = 0; h_attenuation[i] != 0; i++) {
    157			if (h_attenuation[i] >= h_atten)
    158				break;
    159		}
    160
    161		dcgx = i;
    162	}
    163
    164	/* the horizontal scaling increment controls the UV filter
    165	   to reduce the bandwidth to improve the display quality,
    166	   so set it ... */
    167	if ( xsci == 0x400)
    168		pfuv = 0x00;
    169	else if ( xsci < 0x600)
    170		pfuv = 0x01;
    171	else if ( xsci < 0x680)
    172		pfuv = 0x11;
    173	else if ( xsci < 0x700)
    174		pfuv = 0x22;
    175	else
    176		pfuv = 0x33;
    177
    178
    179	*hps_v_gain  &= MASK_W0|MASK_B2;
    180	*hps_v_gain  |= (pfuv << 24);
    181
    182	*hps_h_scale	&= ~(MASK_W1 | 0xf000);
    183	*hps_h_scale	|= (xim << 31) | (xp << 24) | (xsci << 12);
    184
    185	*hps_h_prescale	|= (dcgx << 27) | ((xpsc-1) << 18) | (xacm << 17) | (cxy << 8) | (cxuv << 0);
    186
    187	return 0;
    188}
    189
    190static struct {
    191	u16 hps_coeff;
    192	u16 weight_sum;
    193} hps_v_coeff_tab [] = {
    194 {0x0100,   2},  {0x0102,   4},  {0x0300,   4},  {0x0106,   8},  {0x0502,   8},
    195 {0x0708,   8},  {0x0F00,   8},  {0x011E,  16},  {0x110E,  16},  {0x1926,  16},
    196 {0x3906,  16},  {0x3D42,  16},  {0x7D02,  16},  {0x7F80,  16},  {0xFF00,  16},
    197 {0x01FE,  32},  {0x01FE,  32},  {0x817E,  32},  {0x817E,  32},  {0xC13E,  32},
    198 {0xC13E,  32},  {0xE11E,  32},  {0xE11E,  32},  {0xF10E,  32},  {0xF10E,  32},
    199 {0xF906,  32},  {0xF906,  32},  {0xFD02,  32},  {0xFD02,  32},  {0xFF00,  32},
    200 {0xFF00,  32},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},
    201 {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},
    202 {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},
    203 {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x01FE,  64},  {0x817E,  64},
    204 {0x817E,  64},  {0xC13E,  64},  {0xC13E,  64},  {0xE11E,  64},  {0xE11E,  64},
    205 {0xF10E,  64},  {0xF10E,  64},  {0xF906,  64},  {0xF906,  64},  {0xFD02,  64},
    206 {0xFD02,  64},  {0xFF00,  64},  {0xFF00,  64},  {0x01FE, 128}
    207};
    208
    209/* table of attenuation values for vertical scaling */
    210static u16 v_attenuation[] = { 2, 4, 8, 16, 32, 64, 128, 256, 0};
    211
    212/* calculate vertical scale registers */
    213static int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field field,
    214	int in_y, int out_y, u32* hps_v_scale, u32* hps_v_gain)
    215{
    216	int lpi = 0;
    217
    218	/* vertical scaling */
    219	u32 yacm = 0, ysci = 0, yacl = 0, ypo = 0, ype = 0;
    220	/* vertical scale & gain */
    221	u32 dcgy = 0, cya_cyb = 0;
    222
    223	/* helper variables */
    224	u32 v_atten = 0, i = 0;
    225
    226	/* error, if vertical zooming */
    227	if ( in_y < out_y ) {
    228		return -EINVAL;
    229	}
    230
    231	/* linear phase interpolation may be used
    232	   if scaling is between 1 and 1/2 (both fields used)
    233	   or scaling is between 1/2 and 1/4 (if only one field is used) */
    234
    235	if (V4L2_FIELD_HAS_BOTH(field)) {
    236		if( 2*out_y >= in_y) {
    237			lpi = 1;
    238		}
    239	} else if (field == V4L2_FIELD_TOP
    240		|| field == V4L2_FIELD_ALTERNATE
    241		|| field == V4L2_FIELD_BOTTOM) {
    242		if( 4*out_y >= in_y ) {
    243			lpi = 1;
    244		}
    245		out_y *= 2;
    246	}
    247	if( 0 != lpi ) {
    248
    249		yacm = 0;
    250		yacl = 0;
    251		cya_cyb = 0x00ff;
    252
    253		/* calculate scaling increment */
    254		if ( in_y > out_y )
    255			ysci = ((1024 * in_y) / (out_y + 1)) - 1024;
    256		else
    257			ysci = 0;
    258
    259		dcgy = 0;
    260
    261		/* calculate ype and ypo */
    262		ype = ysci / 16;
    263		ypo = ype + (ysci / 64);
    264
    265	} else {
    266		yacm = 1;
    267
    268		/* calculate scaling increment */
    269		ysci = (((10 * 1024 * (in_y - out_y - 1)) / in_y) + 9) / 10;
    270
    271		/* calculate ype and ypo */
    272		ypo = ype = ((ysci + 15) / 16);
    273
    274		/* the sequence length interval (yacl) has to be set according
    275		   to the prescale value, e.g.	[n   .. 1/2) : 0
    276						[1/2 .. 1/3) : 1
    277						[1/3 .. 1/4) : 2
    278						... */
    279		if ( ysci < 512) {
    280			yacl = 0;
    281		} else {
    282			yacl = ( ysci / (1024 - ysci) );
    283		}
    284
    285		/* get filter coefficients for cya, cyb from table hps_v_coeff_tab */
    286		cya_cyb = hps_v_coeff_tab[ (yacl < 63 ? yacl : 63 ) ].hps_coeff;
    287
    288		/* get best match in the table of attenuations for vertical scaling */
    289		v_atten = hps_v_coeff_tab[ (yacl < 63 ? yacl : 63 ) ].weight_sum;
    290
    291		for (i = 0; v_attenuation[i] != 0; i++) {
    292			if (v_attenuation[i] >= v_atten)
    293				break;
    294		}
    295
    296		dcgy = i;
    297	}
    298
    299	/* ypo and ype swapped in spec ? */
    300	*hps_v_scale	|= (yacm << 31) | (ysci << 21) | (yacl << 15) | (ypo << 8 ) | (ype << 1);
    301
    302	*hps_v_gain	&= ~(MASK_W0|MASK_B2);
    303	*hps_v_gain	|= (dcgy << 16) | (cya_cyb << 0);
    304
    305	return 0;
    306}
    307
    308/* simple bubble-sort algorithm with duplicate elimination */
    309static int sort_and_eliminate(u32* values, int* count)
    310{
    311	int low = 0, high = 0, top = 0;
    312	int cur = 0, next = 0;
    313
    314	/* sanity checks */
    315	if( (0 > *count) || (NULL == values) ) {
    316		return -EINVAL;
    317	}
    318
    319	/* bubble sort the first @count items of the array @values */
    320	for( top = *count; top > 0; top--) {
    321		for( low = 0, high = 1; high < top; low++, high++) {
    322			if( values[low] > values[high] )
    323				swap(values[low], values[high]);
    324		}
    325	}
    326
    327	/* remove duplicate items */
    328	for( cur = 0, next = 1; next < *count; next++) {
    329		if( values[cur] != values[next])
    330			values[++cur] = values[next];
    331	}
    332
    333	*count = cur + 1;
    334
    335	return 0;
    336}
    337
    338static void calculate_clipping_registers_rect(struct saa7146_dev *dev, struct saa7146_fh *fh,
    339	struct saa7146_video_dma *vdma2, u32* clip_format, u32* arbtr_ctrl, enum v4l2_field field)
    340{
    341	struct saa7146_vv *vv = dev->vv_data;
    342	__le32 *clipping = vv->d_clipping.cpu_addr;
    343
    344	int width = vv->ov.win.w.width;
    345	int height =  vv->ov.win.w.height;
    346	int clipcount = vv->ov.nclips;
    347
    348	u32 line_list[32];
    349	u32 pixel_list[32];
    350	int numdwords = 0;
    351
    352	int i = 0, j = 0;
    353	int cnt_line = 0, cnt_pixel = 0;
    354
    355	int x[32], y[32], w[32], h[32];
    356
    357	/* clear out memory */
    358	memset(&line_list[0],  0x00, sizeof(u32)*32);
    359	memset(&pixel_list[0], 0x00, sizeof(u32)*32);
    360	memset(clipping,  0x00, SAA7146_CLIPPING_MEM);
    361
    362	/* fill the line and pixel-lists */
    363	for(i = 0; i < clipcount; i++) {
    364		int l = 0, r = 0, t = 0, b = 0;
    365
    366		x[i] = vv->ov.clips[i].c.left;
    367		y[i] = vv->ov.clips[i].c.top;
    368		w[i] = vv->ov.clips[i].c.width;
    369		h[i] = vv->ov.clips[i].c.height;
    370
    371		if( w[i] < 0) {
    372			x[i] += w[i]; w[i] = -w[i];
    373		}
    374		if( h[i] < 0) {
    375			y[i] += h[i]; h[i] = -h[i];
    376		}
    377		if( x[i] < 0) {
    378			w[i] += x[i]; x[i] = 0;
    379		}
    380		if( y[i] < 0) {
    381			h[i] += y[i]; y[i] = 0;
    382		}
    383		if( 0 != vv->vflip ) {
    384			y[i] = height - y[i] - h[i];
    385		}
    386
    387		l = x[i];
    388		r = x[i]+w[i];
    389		t = y[i];
    390		b = y[i]+h[i];
    391
    392		/* insert left/right coordinates */
    393		pixel_list[ 2*i   ] = min_t(int, l, width);
    394		pixel_list[(2*i)+1] = min_t(int, r, width);
    395		/* insert top/bottom coordinates */
    396		line_list[ 2*i   ] = min_t(int, t, height);
    397		line_list[(2*i)+1] = min_t(int, b, height);
    398	}
    399
    400	/* sort and eliminate lists */
    401	cnt_line = cnt_pixel = 2*clipcount;
    402	sort_and_eliminate( &pixel_list[0], &cnt_pixel );
    403	sort_and_eliminate( &line_list[0], &cnt_line );
    404
    405	/* calculate the number of used u32s */
    406	numdwords = max_t(int, (cnt_line+1), (cnt_pixel+1))*2;
    407	numdwords = max_t(int, 4, numdwords);
    408	numdwords = min_t(int, 64, numdwords);
    409
    410	/* fill up cliptable */
    411	for(i = 0; i < cnt_pixel; i++) {
    412		clipping[2*i] |= cpu_to_le32(pixel_list[i] << 16);
    413	}
    414	for(i = 0; i < cnt_line; i++) {
    415		clipping[(2*i)+1] |= cpu_to_le32(line_list[i] << 16);
    416	}
    417
    418	/* fill up cliptable with the display infos */
    419	for(j = 0; j < clipcount; j++) {
    420
    421		for(i = 0; i < cnt_pixel; i++) {
    422
    423			if( x[j] < 0)
    424				x[j] = 0;
    425
    426			if( pixel_list[i] < (x[j] + w[j])) {
    427
    428				if ( pixel_list[i] >= x[j] ) {
    429					clipping[2*i] |= cpu_to_le32(1 << j);
    430				}
    431			}
    432		}
    433		for(i = 0; i < cnt_line; i++) {
    434
    435			if( y[j] < 0)
    436				y[j] = 0;
    437
    438			if( line_list[i] < (y[j] + h[j]) ) {
    439
    440				if( line_list[i] >= y[j] ) {
    441					clipping[(2*i)+1] |= cpu_to_le32(1 << j);
    442				}
    443			}
    444		}
    445	}
    446
    447	/* adjust arbitration control register */
    448	*arbtr_ctrl &= 0xffff00ff;
    449	*arbtr_ctrl |= 0x00001c00;
    450
    451	vdma2->base_even	= vv->d_clipping.dma_handle;
    452	vdma2->base_odd		= vv->d_clipping.dma_handle;
    453	vdma2->prot_addr	= vv->d_clipping.dma_handle+((sizeof(u32))*(numdwords));
    454	vdma2->base_page	= 0x04;
    455	vdma2->pitch		= 0x00;
    456	vdma2->num_line_byte	= (0 << 16 | (sizeof(u32))*(numdwords-1) );
    457
    458	/* set clipping-mode. this depends on the field(s) used */
    459	*clip_format &= 0xfffffff7;
    460	if (V4L2_FIELD_HAS_BOTH(field)) {
    461		*clip_format |= 0x00000008;
    462	} else {
    463		*clip_format |= 0x00000000;
    464	}
    465}
    466
    467/* disable clipping */
    468static void saa7146_disable_clipping(struct saa7146_dev *dev)
    469{
    470	u32 clip_format	= saa7146_read(dev, CLIP_FORMAT_CTRL);
    471
    472	/* mask out relevant bits (=lower word)*/
    473	clip_format &= MASK_W1;
    474
    475	/* upload clipping-registers*/
    476	saa7146_write(dev, CLIP_FORMAT_CTRL,clip_format);
    477	saa7146_write(dev, MC2, (MASK_05 | MASK_21));
    478
    479	/* disable video dma2 */
    480	saa7146_write(dev, MC1, MASK_21);
    481}
    482
    483static void saa7146_set_clipping_rect(struct saa7146_fh *fh)
    484{
    485	struct saa7146_dev *dev = fh->dev;
    486	struct saa7146_vv *vv = dev->vv_data;
    487	enum v4l2_field field = vv->ov.win.field;
    488	struct	saa7146_video_dma vdma2;
    489	u32 clip_format;
    490	u32 arbtr_ctrl;
    491
    492	/* check clipcount, disable clipping if clipcount == 0*/
    493	if (vv->ov.nclips == 0) {
    494		saa7146_disable_clipping(dev);
    495		return;
    496	}
    497
    498	clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL);
    499	arbtr_ctrl = saa7146_read(dev, PCI_BT_V1);
    500
    501	calculate_clipping_registers_rect(dev, fh, &vdma2, &clip_format, &arbtr_ctrl, field);
    502
    503	/* set clipping format */
    504	clip_format &= 0xffff0008;
    505	clip_format |= (SAA7146_CLIPPING_RECT << 4);
    506
    507	/* prepare video dma2 */
    508	saa7146_write(dev, BASE_EVEN2,		vdma2.base_even);
    509	saa7146_write(dev, BASE_ODD2,		vdma2.base_odd);
    510	saa7146_write(dev, PROT_ADDR2,		vdma2.prot_addr);
    511	saa7146_write(dev, BASE_PAGE2,		vdma2.base_page);
    512	saa7146_write(dev, PITCH2,		vdma2.pitch);
    513	saa7146_write(dev, NUM_LINE_BYTE2,	vdma2.num_line_byte);
    514
    515	/* prepare the rest */
    516	saa7146_write(dev, CLIP_FORMAT_CTRL,clip_format);
    517	saa7146_write(dev, PCI_BT_V1, arbtr_ctrl);
    518
    519	/* upload clip_control-register, clipping-registers, enable video dma2 */
    520	saa7146_write(dev, MC2, (MASK_05 | MASK_21 | MASK_03 | MASK_19));
    521	saa7146_write(dev, MC1, (MASK_05 | MASK_21));
    522}
    523
    524static void saa7146_set_window(struct saa7146_dev *dev, int width, int height, enum v4l2_field field)
    525{
    526	struct saa7146_vv *vv = dev->vv_data;
    527
    528	int source = vv->current_hps_source;
    529	int sync = vv->current_hps_sync;
    530
    531	u32 hps_v_scale = 0, hps_v_gain  = 0, hps_ctrl = 0, hps_h_prescale = 0, hps_h_scale = 0;
    532
    533	/* set vertical scale */
    534	hps_v_scale = 0; /* all bits get set by the function-call */
    535	hps_v_gain  = 0; /* fixme: saa7146_read(dev, HPS_V_GAIN);*/
    536	calculate_v_scale_registers(dev, field, vv->standard->v_field*2, height, &hps_v_scale, &hps_v_gain);
    537
    538	/* set horizontal scale */
    539	hps_ctrl	= 0;
    540	hps_h_prescale	= 0; /* all bits get set in the function */
    541	hps_h_scale	= 0;
    542	calculate_h_scale_registers(dev, vv->standard->h_pixels, width, vv->hflip, &hps_ctrl, &hps_v_gain, &hps_h_prescale, &hps_h_scale);
    543
    544	/* set hyo and hxo */
    545	calculate_hxo_and_hyo(vv, &hps_h_scale, &hps_ctrl);
    546	calculate_hps_source_and_sync(dev, source, sync, &hps_ctrl);
    547
    548	/* write out new register contents */
    549	saa7146_write(dev, HPS_V_SCALE,	hps_v_scale);
    550	saa7146_write(dev, HPS_V_GAIN,	hps_v_gain);
    551	saa7146_write(dev, HPS_CTRL,	hps_ctrl);
    552	saa7146_write(dev, HPS_H_PRESCALE,hps_h_prescale);
    553	saa7146_write(dev, HPS_H_SCALE,	hps_h_scale);
    554
    555	/* upload shadow-ram registers */
    556	saa7146_write(dev, MC2, (MASK_05 | MASK_06 | MASK_21 | MASK_22) );
    557}
    558
    559/* calculate the new memory offsets for a desired position */
    560static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field, u32 pixelformat)
    561{
    562	struct saa7146_vv *vv = dev->vv_data;
    563	struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pixelformat);
    564
    565	int b_depth = vv->ov_fmt->depth;
    566	int b_bpl = vv->ov_fb.fmt.bytesperline;
    567	/* The unsigned long cast is to remove a 64-bit compile warning since
    568	   it looks like a 64-bit address is cast to a 32-bit value, even
    569	   though the base pointer is really a 32-bit physical address that
    570	   goes into a 32-bit DMA register.
    571	   FIXME: might not work on some 64-bit platforms, but see the FIXME
    572	   in struct v4l2_framebuffer (videodev2.h) for that.
    573	 */
    574	u32 base = (u32)(unsigned long)vv->ov_fb.base;
    575
    576	struct	saa7146_video_dma vdma1;
    577
    578	/* calculate memory offsets for picture, look if we shall top-down-flip */
    579	vdma1.pitch	= 2*b_bpl;
    580	if ( 0 == vv->vflip ) {
    581		vdma1.base_even = base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
    582		vdma1.base_odd  = vdma1.base_even + (vdma1.pitch / 2);
    583		vdma1.prot_addr = vdma1.base_even + (w_height * (vdma1.pitch / 2));
    584	}
    585	else {
    586		vdma1.base_even = base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8));
    587		vdma1.base_odd  = vdma1.base_even - (vdma1.pitch / 2);
    588		vdma1.prot_addr = vdma1.base_odd - (w_height * (vdma1.pitch / 2));
    589	}
    590
    591	if (V4L2_FIELD_HAS_BOTH(field)) {
    592	} else if (field == V4L2_FIELD_ALTERNATE) {
    593		/* fixme */
    594		vdma1.base_odd = vdma1.prot_addr;
    595		vdma1.pitch /= 2;
    596	} else if (field == V4L2_FIELD_TOP) {
    597		vdma1.base_odd = vdma1.prot_addr;
    598		vdma1.pitch /= 2;
    599	} else if (field == V4L2_FIELD_BOTTOM) {
    600		vdma1.base_odd = vdma1.base_even;
    601		vdma1.base_even = vdma1.prot_addr;
    602		vdma1.pitch /= 2;
    603	}
    604
    605	if ( 0 != vv->vflip ) {
    606		vdma1.pitch *= -1;
    607	}
    608
    609	vdma1.base_page = sfmt->swap;
    610	vdma1.num_line_byte = (vv->standard->v_field<<16)+vv->standard->h_pixels;
    611
    612	saa7146_write_out_dma(dev, 1, &vdma1);
    613}
    614
    615static void saa7146_set_output_format(struct saa7146_dev *dev, unsigned long palette)
    616{
    617	u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL);
    618
    619	/* call helper function */
    620	calculate_output_format_register(dev,palette,&clip_format);
    621
    622	/* update the hps registers */
    623	saa7146_write(dev, CLIP_FORMAT_CTRL, clip_format);
    624	saa7146_write(dev, MC2, (MASK_05 | MASK_21));
    625}
    626
    627/* select input-source */
    628void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync)
    629{
    630	struct saa7146_vv *vv = dev->vv_data;
    631	u32 hps_ctrl = 0;
    632
    633	/* read old state */
    634	hps_ctrl = saa7146_read(dev, HPS_CTRL);
    635
    636	hps_ctrl &= ~( MASK_31 | MASK_30 | MASK_28 );
    637	hps_ctrl |= (source << 30) | (sync << 28);
    638
    639	/* write back & upload register */
    640	saa7146_write(dev, HPS_CTRL, hps_ctrl);
    641	saa7146_write(dev, MC2, (MASK_05 | MASK_21));
    642
    643	vv->current_hps_source = source;
    644	vv->current_hps_sync = sync;
    645}
    646EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync);
    647
    648int saa7146_enable_overlay(struct saa7146_fh *fh)
    649{
    650	struct saa7146_dev *dev = fh->dev;
    651	struct saa7146_vv *vv = dev->vv_data;
    652
    653	saa7146_set_window(dev, vv->ov.win.w.width, vv->ov.win.w.height, vv->ov.win.field);
    654	saa7146_set_position(dev, vv->ov.win.w.left, vv->ov.win.w.top, vv->ov.win.w.height, vv->ov.win.field, vv->ov_fmt->pixelformat);
    655	saa7146_set_output_format(dev, vv->ov_fmt->trans);
    656	saa7146_set_clipping_rect(fh);
    657
    658	/* enable video dma1 */
    659	saa7146_write(dev, MC1, (MASK_06 | MASK_22));
    660	return 0;
    661}
    662
    663void saa7146_disable_overlay(struct saa7146_fh *fh)
    664{
    665	struct saa7146_dev *dev = fh->dev;
    666
    667	/* disable clipping + video dma1 */
    668	saa7146_disable_clipping(dev);
    669	saa7146_write(dev, MC1, MASK_22);
    670}
    671
    672void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma)
    673{
    674	int where = 0;
    675
    676	if( which < 1 || which > 3) {
    677		return;
    678	}
    679
    680	/* calculate starting address */
    681	where  = (which-1)*0x18;
    682
    683	saa7146_write(dev, where,	vdma->base_odd);
    684	saa7146_write(dev, where+0x04,	vdma->base_even);
    685	saa7146_write(dev, where+0x08,	vdma->prot_addr);
    686	saa7146_write(dev, where+0x0c,	vdma->pitch);
    687	saa7146_write(dev, where+0x10,	vdma->base_page);
    688	saa7146_write(dev, where+0x14,	vdma->num_line_byte);
    689
    690	/* upload */
    691	saa7146_write(dev, MC2, (MASK_02<<(which-1))|(MASK_18<<(which-1)));
    692/*
    693	printk("vdma%d.base_even:     0x%08x\n", which,vdma->base_even);
    694	printk("vdma%d.base_odd:      0x%08x\n", which,vdma->base_odd);
    695	printk("vdma%d.prot_addr:     0x%08x\n", which,vdma->prot_addr);
    696	printk("vdma%d.base_page:     0x%08x\n", which,vdma->base_page);
    697	printk("vdma%d.pitch:         0x%08x\n", which,vdma->pitch);
    698	printk("vdma%d.num_line_byte: 0x%08x\n", which,vdma->num_line_byte);
    699*/
    700}
    701
    702static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa7146_buf *buf)
    703{
    704	struct saa7146_vv *vv = dev->vv_data;
    705	struct saa7146_video_dma vdma1;
    706
    707	struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
    708
    709	int width = buf->fmt->width;
    710	int height = buf->fmt->height;
    711	int bytesperline = buf->fmt->bytesperline;
    712	enum v4l2_field field = buf->fmt->field;
    713
    714	int depth = sfmt->depth;
    715
    716	DEB_CAP("[size=%dx%d,fields=%s]\n",
    717		width, height, v4l2_field_names[field]);
    718
    719	if( bytesperline != 0) {
    720		vdma1.pitch = bytesperline*2;
    721	} else {
    722		vdma1.pitch = (width*depth*2)/8;
    723	}
    724	vdma1.num_line_byte	= ((vv->standard->v_field<<16) + vv->standard->h_pixels);
    725	vdma1.base_page		= buf->pt[0].dma | ME1 | sfmt->swap;
    726
    727	if( 0 != vv->vflip ) {
    728		vdma1.prot_addr	= buf->pt[0].offset;
    729		vdma1.base_even	= buf->pt[0].offset+(vdma1.pitch/2)*height;
    730		vdma1.base_odd	= vdma1.base_even - (vdma1.pitch/2);
    731	} else {
    732		vdma1.base_even	= buf->pt[0].offset;
    733		vdma1.base_odd	= vdma1.base_even + (vdma1.pitch/2);
    734		vdma1.prot_addr	= buf->pt[0].offset+(vdma1.pitch/2)*height;
    735	}
    736
    737	if (V4L2_FIELD_HAS_BOTH(field)) {
    738	} else if (field == V4L2_FIELD_ALTERNATE) {
    739		/* fixme */
    740		if ( vv->last_field == V4L2_FIELD_TOP ) {
    741			vdma1.base_odd	= vdma1.prot_addr;
    742			vdma1.pitch /= 2;
    743		} else if ( vv->last_field == V4L2_FIELD_BOTTOM ) {
    744			vdma1.base_odd	= vdma1.base_even;
    745			vdma1.base_even = vdma1.prot_addr;
    746			vdma1.pitch /= 2;
    747		}
    748	} else if (field == V4L2_FIELD_TOP) {
    749		vdma1.base_odd	= vdma1.prot_addr;
    750		vdma1.pitch /= 2;
    751	} else if (field == V4L2_FIELD_BOTTOM) {
    752		vdma1.base_odd	= vdma1.base_even;
    753		vdma1.base_even = vdma1.prot_addr;
    754		vdma1.pitch /= 2;
    755	}
    756
    757	if( 0 != vv->vflip ) {
    758		vdma1.pitch *= -1;
    759	}
    760
    761	saa7146_write_out_dma(dev, 1, &vdma1);
    762	return 0;
    763}
    764
    765static int calc_planar_422(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3)
    766{
    767	int height = buf->fmt->height;
    768	int width = buf->fmt->width;
    769
    770	vdma2->pitch	= width;
    771	vdma3->pitch	= width;
    772
    773	/* fixme: look at bytesperline! */
    774
    775	if( 0 != vv->vflip ) {
    776		vdma2->prot_addr	= buf->pt[1].offset;
    777		vdma2->base_even	= ((vdma2->pitch/2)*height)+buf->pt[1].offset;
    778		vdma2->base_odd		= vdma2->base_even - (vdma2->pitch/2);
    779
    780		vdma3->prot_addr	= buf->pt[2].offset;
    781		vdma3->base_even	= ((vdma3->pitch/2)*height)+buf->pt[2].offset;
    782		vdma3->base_odd		= vdma3->base_even - (vdma3->pitch/2);
    783	} else {
    784		vdma3->base_even	= buf->pt[2].offset;
    785		vdma3->base_odd		= vdma3->base_even + (vdma3->pitch/2);
    786		vdma3->prot_addr	= (vdma3->pitch/2)*height+buf->pt[2].offset;
    787
    788		vdma2->base_even	= buf->pt[1].offset;
    789		vdma2->base_odd		= vdma2->base_even + (vdma2->pitch/2);
    790		vdma2->prot_addr	= (vdma2->pitch/2)*height+buf->pt[1].offset;
    791	}
    792
    793	return 0;
    794}
    795
    796static int calc_planar_420(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3)
    797{
    798	int height = buf->fmt->height;
    799	int width = buf->fmt->width;
    800
    801	vdma2->pitch	= width/2;
    802	vdma3->pitch	= width/2;
    803
    804	if( 0 != vv->vflip ) {
    805		vdma2->prot_addr	= buf->pt[2].offset;
    806		vdma2->base_even	= ((vdma2->pitch/2)*height)+buf->pt[2].offset;
    807		vdma2->base_odd		= vdma2->base_even - (vdma2->pitch/2);
    808
    809		vdma3->prot_addr	= buf->pt[1].offset;
    810		vdma3->base_even	= ((vdma3->pitch/2)*height)+buf->pt[1].offset;
    811		vdma3->base_odd		= vdma3->base_even - (vdma3->pitch/2);
    812
    813	} else {
    814		vdma3->base_even	= buf->pt[2].offset;
    815		vdma3->base_odd		= vdma3->base_even + (vdma3->pitch);
    816		vdma3->prot_addr	= (vdma3->pitch/2)*height+buf->pt[2].offset;
    817
    818		vdma2->base_even	= buf->pt[1].offset;
    819		vdma2->base_odd		= vdma2->base_even + (vdma2->pitch);
    820		vdma2->prot_addr	= (vdma2->pitch/2)*height+buf->pt[1].offset;
    821	}
    822	return 0;
    823}
    824
    825static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa7146_buf *buf)
    826{
    827	struct saa7146_vv *vv = dev->vv_data;
    828	struct saa7146_video_dma vdma1;
    829	struct saa7146_video_dma vdma2;
    830	struct saa7146_video_dma vdma3;
    831
    832	struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
    833
    834	int width = buf->fmt->width;
    835	int height = buf->fmt->height;
    836	enum v4l2_field field = buf->fmt->field;
    837
    838	BUG_ON(0 == buf->pt[0].dma);
    839	BUG_ON(0 == buf->pt[1].dma);
    840	BUG_ON(0 == buf->pt[2].dma);
    841
    842	DEB_CAP("[size=%dx%d,fields=%s]\n",
    843		width, height, v4l2_field_names[field]);
    844
    845	/* fixme: look at bytesperline! */
    846
    847	/* fixme: what happens for user space buffers here?. The offsets are
    848	   most likely wrong, this version here only works for page-aligned
    849	   buffers, modifications to the pagetable-functions are necessary...*/
    850
    851	vdma1.pitch		= width*2;
    852	vdma1.num_line_byte	= ((vv->standard->v_field<<16) + vv->standard->h_pixels);
    853	vdma1.base_page		= buf->pt[0].dma | ME1;
    854
    855	if( 0 != vv->vflip ) {
    856		vdma1.prot_addr	= buf->pt[0].offset;
    857		vdma1.base_even	= ((vdma1.pitch/2)*height)+buf->pt[0].offset;
    858		vdma1.base_odd	= vdma1.base_even - (vdma1.pitch/2);
    859	} else {
    860		vdma1.base_even	= buf->pt[0].offset;
    861		vdma1.base_odd	= vdma1.base_even + (vdma1.pitch/2);
    862		vdma1.prot_addr	= (vdma1.pitch/2)*height+buf->pt[0].offset;
    863	}
    864
    865	vdma2.num_line_byte	= 0; /* unused */
    866	vdma2.base_page		= buf->pt[1].dma | ME1;
    867
    868	vdma3.num_line_byte	= 0; /* unused */
    869	vdma3.base_page		= buf->pt[2].dma | ME1;
    870
    871	switch( sfmt->depth ) {
    872		case 12: {
    873			calc_planar_420(vv,buf,&vdma2,&vdma3);
    874			break;
    875		}
    876		case 16: {
    877			calc_planar_422(vv,buf,&vdma2,&vdma3);
    878			break;
    879		}
    880		default: {
    881			return -1;
    882		}
    883	}
    884
    885	if (V4L2_FIELD_HAS_BOTH(field)) {
    886	} else if (field == V4L2_FIELD_ALTERNATE) {
    887		/* fixme */
    888		vdma1.base_odd	= vdma1.prot_addr;
    889		vdma1.pitch /= 2;
    890		vdma2.base_odd	= vdma2.prot_addr;
    891		vdma2.pitch /= 2;
    892		vdma3.base_odd	= vdma3.prot_addr;
    893		vdma3.pitch /= 2;
    894	} else if (field == V4L2_FIELD_TOP) {
    895		vdma1.base_odd	= vdma1.prot_addr;
    896		vdma1.pitch /= 2;
    897		vdma2.base_odd	= vdma2.prot_addr;
    898		vdma2.pitch /= 2;
    899		vdma3.base_odd	= vdma3.prot_addr;
    900		vdma3.pitch /= 2;
    901	} else if (field == V4L2_FIELD_BOTTOM) {
    902		vdma1.base_odd	= vdma1.base_even;
    903		vdma1.base_even = vdma1.prot_addr;
    904		vdma1.pitch /= 2;
    905		vdma2.base_odd	= vdma2.base_even;
    906		vdma2.base_even = vdma2.prot_addr;
    907		vdma2.pitch /= 2;
    908		vdma3.base_odd	= vdma3.base_even;
    909		vdma3.base_even = vdma3.prot_addr;
    910		vdma3.pitch /= 2;
    911	}
    912
    913	if( 0 != vv->vflip ) {
    914		vdma1.pitch *= -1;
    915		vdma2.pitch *= -1;
    916		vdma3.pitch *= -1;
    917	}
    918
    919	saa7146_write_out_dma(dev, 1, &vdma1);
    920	if( (sfmt->flags & FORMAT_BYTE_SWAP) != 0 ) {
    921		saa7146_write_out_dma(dev, 3, &vdma2);
    922		saa7146_write_out_dma(dev, 2, &vdma3);
    923	} else {
    924		saa7146_write_out_dma(dev, 2, &vdma2);
    925		saa7146_write_out_dma(dev, 3, &vdma3);
    926	}
    927	return 0;
    928}
    929
    930static void program_capture_engine(struct saa7146_dev *dev, int planar)
    931{
    932	struct saa7146_vv *vv = dev->vv_data;
    933	int count = 0;
    934
    935	unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B;
    936	unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B;
    937
    938	/* wait for o_fid_a/b / e_fid_a/b toggle only if rps register 0 is not set*/
    939	WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | o_wait);
    940	WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | e_wait);
    941
    942	/* set rps register 0 */
    943	WRITE_RPS0(CMD_WR_REG | (1 << 8) | (MC2/4));
    944	WRITE_RPS0(MASK_27 | MASK_11);
    945
    946	/* turn on video-dma1 */
    947	WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
    948	WRITE_RPS0(MASK_06 | MASK_22);			/* => mask */
    949	WRITE_RPS0(MASK_06 | MASK_22);			/* => values */
    950	if( 0 != planar ) {
    951		/* turn on video-dma2 */
    952		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
    953		WRITE_RPS0(MASK_05 | MASK_21);			/* => mask */
    954		WRITE_RPS0(MASK_05 | MASK_21);			/* => values */
    955
    956		/* turn on video-dma3 */
    957		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
    958		WRITE_RPS0(MASK_04 | MASK_20);			/* => mask */
    959		WRITE_RPS0(MASK_04 | MASK_20);			/* => values */
    960	}
    961
    962	/* wait for o_fid_a/b / e_fid_a/b toggle */
    963	if ( vv->last_field == V4L2_FIELD_INTERLACED ) {
    964		WRITE_RPS0(CMD_PAUSE | o_wait);
    965		WRITE_RPS0(CMD_PAUSE | e_wait);
    966	} else if ( vv->last_field == V4L2_FIELD_TOP ) {
    967		WRITE_RPS0(CMD_PAUSE | (vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? MASK_10 : MASK_09));
    968		WRITE_RPS0(CMD_PAUSE | o_wait);
    969	} else if ( vv->last_field == V4L2_FIELD_BOTTOM ) {
    970		WRITE_RPS0(CMD_PAUSE | (vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? MASK_10 : MASK_09));
    971		WRITE_RPS0(CMD_PAUSE | e_wait);
    972	}
    973
    974	/* turn off video-dma1 */
    975	WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
    976	WRITE_RPS0(MASK_22 | MASK_06);			/* => mask */
    977	WRITE_RPS0(MASK_22);				/* => values */
    978	if( 0 != planar ) {
    979		/* turn off video-dma2 */
    980		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
    981		WRITE_RPS0(MASK_05 | MASK_21);			/* => mask */
    982		WRITE_RPS0(MASK_21);				/* => values */
    983
    984		/* turn off video-dma3 */
    985		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));
    986		WRITE_RPS0(MASK_04 | MASK_20);			/* => mask */
    987		WRITE_RPS0(MASK_20);				/* => values */
    988	}
    989
    990	/* generate interrupt */
    991	WRITE_RPS0(CMD_INTERRUPT);
    992
    993	/* stop */
    994	WRITE_RPS0(CMD_STOP);
    995}
    996
    997void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next)
    998{
    999	struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
   1000	struct saa7146_vv *vv = dev->vv_data;
   1001	u32 vdma1_prot_addr;
   1002
   1003	DEB_CAP("buf:%p, next:%p\n", buf, next);
   1004
   1005	vdma1_prot_addr = saa7146_read(dev, PROT_ADDR1);
   1006	if( 0 == vdma1_prot_addr ) {
   1007		/* clear out beginning of streaming bit (rps register 0)*/
   1008		DEB_CAP("forcing sync to new frame\n");
   1009		saa7146_write(dev, MC2, MASK_27 );
   1010	}
   1011
   1012	saa7146_set_window(dev, buf->fmt->width, buf->fmt->height, buf->fmt->field);
   1013	saa7146_set_output_format(dev, sfmt->trans);
   1014	saa7146_disable_clipping(dev);
   1015
   1016	if ( vv->last_field == V4L2_FIELD_INTERLACED ) {
   1017	} else if ( vv->last_field == V4L2_FIELD_TOP ) {
   1018		vv->last_field = V4L2_FIELD_BOTTOM;
   1019	} else if ( vv->last_field == V4L2_FIELD_BOTTOM ) {
   1020		vv->last_field = V4L2_FIELD_TOP;
   1021	}
   1022
   1023	if( 0 != IS_PLANAR(sfmt->trans)) {
   1024		calculate_video_dma_grab_planar(dev, buf);
   1025		program_capture_engine(dev,1);
   1026	} else {
   1027		calculate_video_dma_grab_packed(dev, buf);
   1028		program_capture_engine(dev,0);
   1029	}
   1030
   1031/*
   1032	printk("vdma%d.base_even:     0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1));
   1033	printk("vdma%d.base_odd:      0x%08x\n", 1,saa7146_read(dev,BASE_ODD1));
   1034	printk("vdma%d.prot_addr:     0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1));
   1035	printk("vdma%d.base_page:     0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1));
   1036	printk("vdma%d.pitch:         0x%08x\n", 1,saa7146_read(dev,PITCH1));
   1037	printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1));
   1038	printk("vdma%d => vptr      : 0x%08x\n", 1,saa7146_read(dev,PCI_VDP1));
   1039*/
   1040
   1041	/* write the address of the rps-program */
   1042	saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle);
   1043
   1044	/* turn on rps */
   1045	saa7146_write(dev, MC1, (MASK_12 | MASK_28));
   1046}