162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* Linux driver for Philips webcam
362306a36Sopenharmony_ci   Decompression for chipset version 2 et 3
462306a36Sopenharmony_ci   (C) 2004-2006  Luc Saillard (luc@saillard.org)
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
762306a36Sopenharmony_ci   driver and thus may have bugs that are not present in the original version.
862306a36Sopenharmony_ci   Please send bug reports and support requests to <luc@saillard.org>.
962306a36Sopenharmony_ci   The decompression routines have been implemented by reverse-engineering the
1062306a36Sopenharmony_ci   Nemosoft binary pwcx module. Caveat emptor.
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci*/
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include "pwc-timon.h"
1662306a36Sopenharmony_ci#include "pwc-kiara.h"
1762306a36Sopenharmony_ci#include "pwc-dec23.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <linux/string.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/*
2362306a36Sopenharmony_ci * USE_LOOKUP_TABLE_TO_CLAMP
2462306a36Sopenharmony_ci *   0: use a C version of this tests:  {  a<0?0:(a>255?255:a) }
2562306a36Sopenharmony_ci *   1: use a faster lookup table for cpu with a big cache (intel)
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_ci#define USE_LOOKUP_TABLE_TO_CLAMP	1
2862306a36Sopenharmony_ci/*
2962306a36Sopenharmony_ci * UNROLL_LOOP_FOR_COPYING_BLOCK
3062306a36Sopenharmony_ci *   0: use a loop for a smaller code (but little slower)
3162306a36Sopenharmony_ci *   1: when unrolling the loop, gcc produces some faster code (perhaps only
3262306a36Sopenharmony_ci *   valid for intel processor class). Activating this option, automatically
3362306a36Sopenharmony_ci *   activate USE_LOOKUP_TABLE_TO_CLAMP
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci#define UNROLL_LOOP_FOR_COPY		1
3662306a36Sopenharmony_ci#if UNROLL_LOOP_FOR_COPY
3762306a36Sopenharmony_ci# undef USE_LOOKUP_TABLE_TO_CLAMP
3862306a36Sopenharmony_ci# define USE_LOOKUP_TABLE_TO_CLAMP 1
3962306a36Sopenharmony_ci#endif
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic void build_subblock_pattern(struct pwc_dec23_private *pdec)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	static const unsigned int initial_values[12] = {
4462306a36Sopenharmony_ci		-0x526500, -0x221200, 0x221200, 0x526500,
4562306a36Sopenharmony_ci			   -0x3de200, 0x3de200,
4662306a36Sopenharmony_ci		-0x6db480, -0x2d5d00, 0x2d5d00, 0x6db480,
4762306a36Sopenharmony_ci			   -0x12c200, 0x12c200
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	};
5062306a36Sopenharmony_ci	static const unsigned int values_derivated[12] = {
5162306a36Sopenharmony_ci		0xa4ca, 0x4424, -0x4424, -0xa4ca,
5262306a36Sopenharmony_ci			0x7bc4, -0x7bc4,
5362306a36Sopenharmony_ci		0xdb69, 0x5aba, -0x5aba, -0xdb69,
5462306a36Sopenharmony_ci			0x2584, -0x2584
5562306a36Sopenharmony_ci	};
5662306a36Sopenharmony_ci	unsigned int temp_values[12];
5762306a36Sopenharmony_ci	int i, j;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	memcpy(temp_values, initial_values, sizeof(initial_values));
6062306a36Sopenharmony_ci	for (i = 0; i < 256; i++) {
6162306a36Sopenharmony_ci		for (j = 0; j < 12; j++) {
6262306a36Sopenharmony_ci			pdec->table_subblock[i][j] = temp_values[j];
6362306a36Sopenharmony_ci			temp_values[j] += values_derivated[j];
6462306a36Sopenharmony_ci		}
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic void build_bit_powermask_table(struct pwc_dec23_private *pdec)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	unsigned char *p;
7162306a36Sopenharmony_ci	unsigned int bit, byte, mask, val;
7262306a36Sopenharmony_ci	unsigned int bitpower = 1;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	for (bit = 0; bit < 8; bit++) {
7562306a36Sopenharmony_ci		mask = bitpower - 1;
7662306a36Sopenharmony_ci		p = pdec->table_bitpowermask[bit];
7762306a36Sopenharmony_ci		for (byte = 0; byte < 256; byte++) {
7862306a36Sopenharmony_ci			val = (byte & mask);
7962306a36Sopenharmony_ci			if (byte & bitpower)
8062306a36Sopenharmony_ci				val = -val;
8162306a36Sopenharmony_ci			*p++ = val;
8262306a36Sopenharmony_ci		}
8362306a36Sopenharmony_ci		bitpower<<=1;
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic void build_table_color(const unsigned int romtable[16][8],
8962306a36Sopenharmony_ci			      unsigned char p0004[16][1024],
9062306a36Sopenharmony_ci			      unsigned char p8004[16][256])
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	int compression_mode, j, k, bit, pw;
9362306a36Sopenharmony_ci	unsigned char *p0, *p8;
9462306a36Sopenharmony_ci	const unsigned int *r;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	/* We have 16 compressions tables */
9762306a36Sopenharmony_ci	for (compression_mode = 0; compression_mode < 16; compression_mode++) {
9862306a36Sopenharmony_ci		p0 = p0004[compression_mode];
9962306a36Sopenharmony_ci		p8 = p8004[compression_mode];
10062306a36Sopenharmony_ci		r  = romtable[compression_mode];
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci		for (j = 0; j < 8; j++, r++, p0 += 128) {
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci			for (k = 0; k < 16; k++) {
10562306a36Sopenharmony_ci				if (k == 0)
10662306a36Sopenharmony_ci					bit = 1;
10762306a36Sopenharmony_ci				else if (k >= 1 && k < 3)
10862306a36Sopenharmony_ci					bit = (r[0] >> 15) & 7;
10962306a36Sopenharmony_ci				else if (k >= 3 && k < 6)
11062306a36Sopenharmony_ci					bit = (r[0] >> 12) & 7;
11162306a36Sopenharmony_ci				else if (k >= 6 && k < 10)
11262306a36Sopenharmony_ci					bit = (r[0] >> 9) & 7;
11362306a36Sopenharmony_ci				else if (k >= 10 && k < 13)
11462306a36Sopenharmony_ci					bit = (r[0] >> 6) & 7;
11562306a36Sopenharmony_ci				else if (k >= 13 && k < 15)
11662306a36Sopenharmony_ci					bit = (r[0] >> 3) & 7;
11762306a36Sopenharmony_ci				else
11862306a36Sopenharmony_ci					bit = (r[0]) & 7;
11962306a36Sopenharmony_ci				if (k == 0)
12062306a36Sopenharmony_ci					*p8++ = 8;
12162306a36Sopenharmony_ci				else
12262306a36Sopenharmony_ci					*p8++ = j - bit;
12362306a36Sopenharmony_ci				*p8++ = bit;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci				pw = 1 << bit;
12662306a36Sopenharmony_ci				p0[k + 0x00] = (1 * pw) + 0x80;
12762306a36Sopenharmony_ci				p0[k + 0x10] = (2 * pw) + 0x80;
12862306a36Sopenharmony_ci				p0[k + 0x20] = (3 * pw) + 0x80;
12962306a36Sopenharmony_ci				p0[k + 0x30] = (4 * pw) + 0x80;
13062306a36Sopenharmony_ci				p0[k + 0x40] = (-1 * pw) + 0x80;
13162306a36Sopenharmony_ci				p0[k + 0x50] = (-2 * pw) + 0x80;
13262306a36Sopenharmony_ci				p0[k + 0x60] = (-3 * pw) + 0x80;
13362306a36Sopenharmony_ci				p0[k + 0x70] = (-4 * pw) + 0x80;
13462306a36Sopenharmony_ci			}	/* end of for (k=0; k<16; k++, p8++) */
13562306a36Sopenharmony_ci		}	/* end of for (j=0; j<8; j++ , table++) */
13662306a36Sopenharmony_ci	} /* end of foreach compression_mode */
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci/*
14062306a36Sopenharmony_ci *
14162306a36Sopenharmony_ci */
14262306a36Sopenharmony_cistatic void fill_table_dc00_d800(struct pwc_dec23_private *pdec)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci#define SCALEBITS 15
14562306a36Sopenharmony_ci#define ONE_HALF  (1UL << (SCALEBITS - 1))
14662306a36Sopenharmony_ci	int i;
14762306a36Sopenharmony_ci	unsigned int offset1 = ONE_HALF;
14862306a36Sopenharmony_ci	unsigned int offset2 = 0x0000;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	for (i=0; i<256; i++) {
15162306a36Sopenharmony_ci		pdec->table_dc00[i] = offset1 & ~(ONE_HALF);
15262306a36Sopenharmony_ci		pdec->table_d800[i] = offset2;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci		offset1 += 0x7bc4;
15562306a36Sopenharmony_ci		offset2 += 0x7bc4;
15662306a36Sopenharmony_ci	}
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/*
16062306a36Sopenharmony_ci * To decode the stream:
16162306a36Sopenharmony_ci *   if look_bits(2) == 0:	# op == 2 in the lookup table
16262306a36Sopenharmony_ci *      skip_bits(2)
16362306a36Sopenharmony_ci *      end of the stream
16462306a36Sopenharmony_ci *   elif look_bits(3) == 7:	# op == 1 in the lookup table
16562306a36Sopenharmony_ci *      skip_bits(3)
16662306a36Sopenharmony_ci *      yyyy = get_bits(4)
16762306a36Sopenharmony_ci *      xxxx = get_bits(8)
16862306a36Sopenharmony_ci *   else:			# op == 0 in the lookup table
16962306a36Sopenharmony_ci *      skip_bits(x)
17062306a36Sopenharmony_ci *
17162306a36Sopenharmony_ci * For speedup processing, we build a lookup table and we takes the first 6 bits.
17262306a36Sopenharmony_ci *
17362306a36Sopenharmony_ci * struct {
17462306a36Sopenharmony_ci *   unsigned char op;	    // operation to execute
17562306a36Sopenharmony_ci *   unsigned char bits;    // bits use to perform operation
17662306a36Sopenharmony_ci *   unsigned char offset1; // offset to add to access in the table_0004 % 16
17762306a36Sopenharmony_ci *   unsigned char offset2; // offset to add to access in the table_0004
17862306a36Sopenharmony_ci * }
17962306a36Sopenharmony_ci *
18062306a36Sopenharmony_ci * How to build this table ?
18162306a36Sopenharmony_ci *   op == 2 when (i%4)==0
18262306a36Sopenharmony_ci *   op == 1 when (i%8)==7
18362306a36Sopenharmony_ci *   op == 0 otherwise
18462306a36Sopenharmony_ci *
18562306a36Sopenharmony_ci */
18662306a36Sopenharmony_cistatic const unsigned char hash_table_ops[64*4] = {
18762306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00,
18862306a36Sopenharmony_ci	0x00, 0x03, 0x01, 0x00,
18962306a36Sopenharmony_ci	0x00, 0x04, 0x01, 0x10,
19062306a36Sopenharmony_ci	0x00, 0x06, 0x01, 0x30,
19162306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00,
19262306a36Sopenharmony_ci	0x00, 0x03, 0x01, 0x40,
19362306a36Sopenharmony_ci	0x00, 0x05, 0x01, 0x20,
19462306a36Sopenharmony_ci	0x01, 0x00, 0x00, 0x00,
19562306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00,
19662306a36Sopenharmony_ci	0x00, 0x03, 0x01, 0x00,
19762306a36Sopenharmony_ci	0x00, 0x04, 0x01, 0x50,
19862306a36Sopenharmony_ci	0x00, 0x05, 0x02, 0x00,
19962306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00,
20062306a36Sopenharmony_ci	0x00, 0x03, 0x01, 0x40,
20162306a36Sopenharmony_ci	0x00, 0x05, 0x03, 0x00,
20262306a36Sopenharmony_ci	0x01, 0x00, 0x00, 0x00,
20362306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00,
20462306a36Sopenharmony_ci	0x00, 0x03, 0x01, 0x00,
20562306a36Sopenharmony_ci	0x00, 0x04, 0x01, 0x10,
20662306a36Sopenharmony_ci	0x00, 0x06, 0x02, 0x10,
20762306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00,
20862306a36Sopenharmony_ci	0x00, 0x03, 0x01, 0x40,
20962306a36Sopenharmony_ci	0x00, 0x05, 0x01, 0x60,
21062306a36Sopenharmony_ci	0x01, 0x00, 0x00, 0x00,
21162306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00,
21262306a36Sopenharmony_ci	0x00, 0x03, 0x01, 0x00,
21362306a36Sopenharmony_ci	0x00, 0x04, 0x01, 0x50,
21462306a36Sopenharmony_ci	0x00, 0x05, 0x02, 0x40,
21562306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00,
21662306a36Sopenharmony_ci	0x00, 0x03, 0x01, 0x40,
21762306a36Sopenharmony_ci	0x00, 0x05, 0x03, 0x40,
21862306a36Sopenharmony_ci	0x01, 0x00, 0x00, 0x00,
21962306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00,
22062306a36Sopenharmony_ci	0x00, 0x03, 0x01, 0x00,
22162306a36Sopenharmony_ci	0x00, 0x04, 0x01, 0x10,
22262306a36Sopenharmony_ci	0x00, 0x06, 0x01, 0x70,
22362306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00,
22462306a36Sopenharmony_ci	0x00, 0x03, 0x01, 0x40,
22562306a36Sopenharmony_ci	0x00, 0x05, 0x01, 0x20,
22662306a36Sopenharmony_ci	0x01, 0x00, 0x00, 0x00,
22762306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00,
22862306a36Sopenharmony_ci	0x00, 0x03, 0x01, 0x00,
22962306a36Sopenharmony_ci	0x00, 0x04, 0x01, 0x50,
23062306a36Sopenharmony_ci	0x00, 0x05, 0x02, 0x00,
23162306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00,
23262306a36Sopenharmony_ci	0x00, 0x03, 0x01, 0x40,
23362306a36Sopenharmony_ci	0x00, 0x05, 0x03, 0x00,
23462306a36Sopenharmony_ci	0x01, 0x00, 0x00, 0x00,
23562306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00,
23662306a36Sopenharmony_ci	0x00, 0x03, 0x01, 0x00,
23762306a36Sopenharmony_ci	0x00, 0x04, 0x01, 0x10,
23862306a36Sopenharmony_ci	0x00, 0x06, 0x02, 0x50,
23962306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00,
24062306a36Sopenharmony_ci	0x00, 0x03, 0x01, 0x40,
24162306a36Sopenharmony_ci	0x00, 0x05, 0x01, 0x60,
24262306a36Sopenharmony_ci	0x01, 0x00, 0x00, 0x00,
24362306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00,
24462306a36Sopenharmony_ci	0x00, 0x03, 0x01, 0x00,
24562306a36Sopenharmony_ci	0x00, 0x04, 0x01, 0x50,
24662306a36Sopenharmony_ci	0x00, 0x05, 0x02, 0x40,
24762306a36Sopenharmony_ci	0x02, 0x00, 0x00, 0x00,
24862306a36Sopenharmony_ci	0x00, 0x03, 0x01, 0x40,
24962306a36Sopenharmony_ci	0x00, 0x05, 0x03, 0x40,
25062306a36Sopenharmony_ci	0x01, 0x00, 0x00, 0x00
25162306a36Sopenharmony_ci};
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci/*
25462306a36Sopenharmony_ci *
25562306a36Sopenharmony_ci */
25662306a36Sopenharmony_cistatic const unsigned int MulIdx[16][16] = {
25762306a36Sopenharmony_ci	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
25862306a36Sopenharmony_ci	{0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,},
25962306a36Sopenharmony_ci	{0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,},
26062306a36Sopenharmony_ci	{4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4,},
26162306a36Sopenharmony_ci	{6, 7, 8, 9, 7, 10, 11, 8, 8, 11, 10, 7, 9, 8, 7, 6,},
26262306a36Sopenharmony_ci	{4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4,},
26362306a36Sopenharmony_ci	{1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2,},
26462306a36Sopenharmony_ci	{0, 3, 3, 0, 1, 2, 2, 1, 2, 1, 1, 2, 3, 0, 0, 3,},
26562306a36Sopenharmony_ci	{0, 1, 2, 3, 3, 2, 1, 0, 3, 2, 1, 0, 0, 1, 2, 3,},
26662306a36Sopenharmony_ci	{1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0, 2, 2, 2, 2,},
26762306a36Sopenharmony_ci	{7, 10, 11, 8, 9, 8, 7, 6, 6, 7, 8, 9, 8, 11, 10, 7,},
26862306a36Sopenharmony_ci	{4, 5, 5, 4, 5, 4, 4, 5, 5, 4, 4, 5, 4, 5, 5, 4,},
26962306a36Sopenharmony_ci	{7, 9, 6, 8, 10, 8, 7, 11, 11, 7, 8, 10, 8, 6, 9, 7,},
27062306a36Sopenharmony_ci	{1, 3, 0, 2, 2, 0, 3, 1, 2, 0, 3, 1, 1, 3, 0, 2,},
27162306a36Sopenharmony_ci	{1, 2, 2, 1, 3, 0, 0, 3, 0, 3, 3, 0, 2, 1, 1, 2,},
27262306a36Sopenharmony_ci	{10, 8, 7, 11, 8, 6, 9, 7, 7, 9, 6, 8, 11, 7, 8, 10}
27362306a36Sopenharmony_ci};
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci#if USE_LOOKUP_TABLE_TO_CLAMP
27662306a36Sopenharmony_ci#define MAX_OUTER_CROP_VALUE	(512)
27762306a36Sopenharmony_cistatic unsigned char pwc_crop_table[256 + 2*MAX_OUTER_CROP_VALUE];
27862306a36Sopenharmony_ci#define CLAMP(x) (pwc_crop_table[MAX_OUTER_CROP_VALUE+(x)])
27962306a36Sopenharmony_ci#else
28062306a36Sopenharmony_ci#define CLAMP(x) ((x)>255?255:((x)<0?0:x))
28162306a36Sopenharmony_ci#endif
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci/* If the type or the command change, we rebuild the lookup table */
28562306a36Sopenharmony_civoid pwc_dec23_init(struct pwc_device *pdev, const unsigned char *cmd)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	int flags, version, shift, i;
28862306a36Sopenharmony_ci	struct pwc_dec23_private *pdec = &pdev->dec23;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	mutex_init(&pdec->lock);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	if (pdec->last_cmd_valid && pdec->last_cmd == cmd[2])
29362306a36Sopenharmony_ci		return;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if (DEVICE_USE_CODEC3(pdev->type)) {
29662306a36Sopenharmony_ci		flags = cmd[2] & 0x18;
29762306a36Sopenharmony_ci		if (flags == 8)
29862306a36Sopenharmony_ci			pdec->nbits = 7;	/* More bits, mean more bits to encode the stream, but better quality */
29962306a36Sopenharmony_ci		else if (flags == 0x10)
30062306a36Sopenharmony_ci			pdec->nbits = 8;
30162306a36Sopenharmony_ci		else
30262306a36Sopenharmony_ci			pdec->nbits = 6;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci		version = cmd[2] >> 5;
30562306a36Sopenharmony_ci		build_table_color(KiaraRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1);
30662306a36Sopenharmony_ci		build_table_color(KiaraRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	} else {
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci		flags = cmd[2] & 6;
31162306a36Sopenharmony_ci		if (flags == 2)
31262306a36Sopenharmony_ci			pdec->nbits = 7;
31362306a36Sopenharmony_ci		else if (flags == 4)
31462306a36Sopenharmony_ci			pdec->nbits = 8;
31562306a36Sopenharmony_ci		else
31662306a36Sopenharmony_ci			pdec->nbits = 6;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci		version = cmd[2] >> 3;
31962306a36Sopenharmony_ci		build_table_color(TimonRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1);
32062306a36Sopenharmony_ci		build_table_color(TimonRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2);
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	/* Information can be coded on a variable number of bits but never less than 8 */
32462306a36Sopenharmony_ci	shift = 8 - pdec->nbits;
32562306a36Sopenharmony_ci	pdec->scalebits = SCALEBITS - shift;
32662306a36Sopenharmony_ci	pdec->nbitsmask = 0xFF >> shift;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	fill_table_dc00_d800(pdec);
32962306a36Sopenharmony_ci	build_subblock_pattern(pdec);
33062306a36Sopenharmony_ci	build_bit_powermask_table(pdec);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci#if USE_LOOKUP_TABLE_TO_CLAMP
33362306a36Sopenharmony_ci	/* Build the static table to clamp value [0-255] */
33462306a36Sopenharmony_ci	for (i=0;i<MAX_OUTER_CROP_VALUE;i++)
33562306a36Sopenharmony_ci		pwc_crop_table[i] = 0;
33662306a36Sopenharmony_ci	for (i=0; i<256; i++)
33762306a36Sopenharmony_ci		pwc_crop_table[MAX_OUTER_CROP_VALUE+i] = i;
33862306a36Sopenharmony_ci	for (i=0; i<MAX_OUTER_CROP_VALUE; i++)
33962306a36Sopenharmony_ci		pwc_crop_table[MAX_OUTER_CROP_VALUE+256+i] = 255;
34062306a36Sopenharmony_ci#endif
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	pdec->last_cmd = cmd[2];
34362306a36Sopenharmony_ci	pdec->last_cmd_valid = 1;
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci/*
34762306a36Sopenharmony_ci * Copy the 4x4 image block to Y plane buffer
34862306a36Sopenharmony_ci */
34962306a36Sopenharmony_cistatic void copy_image_block_Y(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci#if UNROLL_LOOP_FOR_COPY
35262306a36Sopenharmony_ci	const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
35362306a36Sopenharmony_ci	const int *c = src;
35462306a36Sopenharmony_ci	unsigned char *d = dst;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	*d++ = cm[c[0] >> scalebits];
35762306a36Sopenharmony_ci	*d++ = cm[c[1] >> scalebits];
35862306a36Sopenharmony_ci	*d++ = cm[c[2] >> scalebits];
35962306a36Sopenharmony_ci	*d++ = cm[c[3] >> scalebits];
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	d = dst + bytes_per_line;
36262306a36Sopenharmony_ci	*d++ = cm[c[4] >> scalebits];
36362306a36Sopenharmony_ci	*d++ = cm[c[5] >> scalebits];
36462306a36Sopenharmony_ci	*d++ = cm[c[6] >> scalebits];
36562306a36Sopenharmony_ci	*d++ = cm[c[7] >> scalebits];
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	d = dst + bytes_per_line*2;
36862306a36Sopenharmony_ci	*d++ = cm[c[8] >> scalebits];
36962306a36Sopenharmony_ci	*d++ = cm[c[9] >> scalebits];
37062306a36Sopenharmony_ci	*d++ = cm[c[10] >> scalebits];
37162306a36Sopenharmony_ci	*d++ = cm[c[11] >> scalebits];
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	d = dst + bytes_per_line*3;
37462306a36Sopenharmony_ci	*d++ = cm[c[12] >> scalebits];
37562306a36Sopenharmony_ci	*d++ = cm[c[13] >> scalebits];
37662306a36Sopenharmony_ci	*d++ = cm[c[14] >> scalebits];
37762306a36Sopenharmony_ci	*d++ = cm[c[15] >> scalebits];
37862306a36Sopenharmony_ci#else
37962306a36Sopenharmony_ci	int i;
38062306a36Sopenharmony_ci	const int *c = src;
38162306a36Sopenharmony_ci	unsigned char *d = dst;
38262306a36Sopenharmony_ci	for (i = 0; i < 4; i++, c++)
38362306a36Sopenharmony_ci		*d++ = CLAMP((*c) >> scalebits);
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	d = dst + bytes_per_line;
38662306a36Sopenharmony_ci	for (i = 0; i < 4; i++, c++)
38762306a36Sopenharmony_ci		*d++ = CLAMP((*c) >> scalebits);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	d = dst + bytes_per_line*2;
39062306a36Sopenharmony_ci	for (i = 0; i < 4; i++, c++)
39162306a36Sopenharmony_ci		*d++ = CLAMP((*c) >> scalebits);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	d = dst + bytes_per_line*3;
39462306a36Sopenharmony_ci	for (i = 0; i < 4; i++, c++)
39562306a36Sopenharmony_ci		*d++ = CLAMP((*c) >> scalebits);
39662306a36Sopenharmony_ci#endif
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci/*
40062306a36Sopenharmony_ci * Copy the 4x4 image block to a CrCb plane buffer
40162306a36Sopenharmony_ci *
40262306a36Sopenharmony_ci */
40362306a36Sopenharmony_cistatic void copy_image_block_CrCb(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci#if UNROLL_LOOP_FOR_COPY
40662306a36Sopenharmony_ci	/* Unroll all loops */
40762306a36Sopenharmony_ci	const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
40862306a36Sopenharmony_ci	const int *c = src;
40962306a36Sopenharmony_ci	unsigned char *d = dst;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	*d++ = cm[c[0] >> scalebits];
41262306a36Sopenharmony_ci	*d++ = cm[c[4] >> scalebits];
41362306a36Sopenharmony_ci	*d++ = cm[c[1] >> scalebits];
41462306a36Sopenharmony_ci	*d++ = cm[c[5] >> scalebits];
41562306a36Sopenharmony_ci	*d++ = cm[c[2] >> scalebits];
41662306a36Sopenharmony_ci	*d++ = cm[c[6] >> scalebits];
41762306a36Sopenharmony_ci	*d++ = cm[c[3] >> scalebits];
41862306a36Sopenharmony_ci	*d++ = cm[c[7] >> scalebits];
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	d = dst + bytes_per_line;
42162306a36Sopenharmony_ci	*d++ = cm[c[12] >> scalebits];
42262306a36Sopenharmony_ci	*d++ = cm[c[8] >> scalebits];
42362306a36Sopenharmony_ci	*d++ = cm[c[13] >> scalebits];
42462306a36Sopenharmony_ci	*d++ = cm[c[9] >> scalebits];
42562306a36Sopenharmony_ci	*d++ = cm[c[14] >> scalebits];
42662306a36Sopenharmony_ci	*d++ = cm[c[10] >> scalebits];
42762306a36Sopenharmony_ci	*d++ = cm[c[15] >> scalebits];
42862306a36Sopenharmony_ci	*d++ = cm[c[11] >> scalebits];
42962306a36Sopenharmony_ci#else
43062306a36Sopenharmony_ci	int i;
43162306a36Sopenharmony_ci	const int *c1 = src;
43262306a36Sopenharmony_ci	const int *c2 = src + 4;
43362306a36Sopenharmony_ci	unsigned char *d = dst;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	for (i = 0; i < 4; i++, c1++, c2++) {
43662306a36Sopenharmony_ci		*d++ = CLAMP((*c1) >> scalebits);
43762306a36Sopenharmony_ci		*d++ = CLAMP((*c2) >> scalebits);
43862306a36Sopenharmony_ci	}
43962306a36Sopenharmony_ci	c1 = src + 12;
44062306a36Sopenharmony_ci	d = dst + bytes_per_line;
44162306a36Sopenharmony_ci	for (i = 0; i < 4; i++, c1++, c2++) {
44262306a36Sopenharmony_ci		*d++ = CLAMP((*c1) >> scalebits);
44362306a36Sopenharmony_ci		*d++ = CLAMP((*c2) >> scalebits);
44462306a36Sopenharmony_ci	}
44562306a36Sopenharmony_ci#endif
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci/*
44962306a36Sopenharmony_ci * To manage the stream, we keep bits in a 32 bits register.
45062306a36Sopenharmony_ci * fill_nbits(n): fill the reservoir with at least n bits
45162306a36Sopenharmony_ci * skip_bits(n): discard n bits from the reservoir
45262306a36Sopenharmony_ci * get_bits(n): fill the reservoir, returns the first n bits and discard the
45362306a36Sopenharmony_ci *              bits from the reservoir.
45462306a36Sopenharmony_ci * __get_nbits(n): faster version of get_bits(n), but asumes that the reservoir
45562306a36Sopenharmony_ci *                 contains at least n bits. bits returned is discarded.
45662306a36Sopenharmony_ci */
45762306a36Sopenharmony_ci#define fill_nbits(pdec, nbits_wanted) do { \
45862306a36Sopenharmony_ci   while (pdec->nbits_in_reservoir<(nbits_wanted)) \
45962306a36Sopenharmony_ci    { \
46062306a36Sopenharmony_ci      pdec->reservoir |= (*(pdec->stream)++) << (pdec->nbits_in_reservoir); \
46162306a36Sopenharmony_ci      pdec->nbits_in_reservoir += 8; \
46262306a36Sopenharmony_ci    } \
46362306a36Sopenharmony_ci}  while(0);
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci#define skip_nbits(pdec, nbits_to_skip) do { \
46662306a36Sopenharmony_ci   pdec->reservoir >>= (nbits_to_skip); \
46762306a36Sopenharmony_ci   pdec->nbits_in_reservoir -= (nbits_to_skip); \
46862306a36Sopenharmony_ci}  while(0);
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci#define get_nbits(pdec, nbits_wanted, result) do { \
47162306a36Sopenharmony_ci   fill_nbits(pdec, nbits_wanted); \
47262306a36Sopenharmony_ci   result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \
47362306a36Sopenharmony_ci   skip_nbits(pdec, nbits_wanted); \
47462306a36Sopenharmony_ci}  while(0);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci#define __get_nbits(pdec, nbits_wanted, result) do { \
47762306a36Sopenharmony_ci   result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \
47862306a36Sopenharmony_ci   skip_nbits(pdec, nbits_wanted); \
47962306a36Sopenharmony_ci}  while(0);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci#define look_nbits(pdec, nbits_wanted) \
48262306a36Sopenharmony_ci   ((pdec->reservoir) & ((1U<<(nbits_wanted))-1))
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci/*
48562306a36Sopenharmony_ci * Decode a 4x4 pixel block
48662306a36Sopenharmony_ci */
48762306a36Sopenharmony_cistatic void decode_block(struct pwc_dec23_private *pdec,
48862306a36Sopenharmony_ci			 const unsigned char *ptable0004,
48962306a36Sopenharmony_ci			 const unsigned char *ptable8004)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	unsigned int primary_color;
49262306a36Sopenharmony_ci	unsigned int channel_v, offset1, op;
49362306a36Sopenharmony_ci	int i;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	fill_nbits(pdec, 16);
49662306a36Sopenharmony_ci	__get_nbits(pdec, pdec->nbits, primary_color);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	if (look_nbits(pdec,2) == 0) {
49962306a36Sopenharmony_ci		skip_nbits(pdec, 2);
50062306a36Sopenharmony_ci		/* Very simple, the color is the same for all pixels of the square */
50162306a36Sopenharmony_ci		for (i = 0; i < 16; i++)
50262306a36Sopenharmony_ci			pdec->temp_colors[i] = pdec->table_dc00[primary_color];
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci		return;
50562306a36Sopenharmony_ci	}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	/* This block is encoded with small pattern */
50862306a36Sopenharmony_ci	for (i = 0; i < 16; i++)
50962306a36Sopenharmony_ci		pdec->temp_colors[i] = pdec->table_d800[primary_color];
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	__get_nbits(pdec, 3, channel_v);
51262306a36Sopenharmony_ci	channel_v = ((channel_v & 1) << 2) | (channel_v & 2) | ((channel_v & 4) >> 2);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	ptable0004 += (channel_v * 128);
51562306a36Sopenharmony_ci	ptable8004 += (channel_v * 32);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	offset1 = 0;
51862306a36Sopenharmony_ci	do
51962306a36Sopenharmony_ci	{
52062306a36Sopenharmony_ci		unsigned int htable_idx, rows = 0;
52162306a36Sopenharmony_ci		const unsigned int *block;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci		/* [  zzzz y x x ]
52462306a36Sopenharmony_ci		 *     xx == 00 :=> end of the block def, remove the two bits from the stream
52562306a36Sopenharmony_ci		 *    yxx == 111
52662306a36Sopenharmony_ci		 *    yxx == any other value
52762306a36Sopenharmony_ci		 *
52862306a36Sopenharmony_ci		 */
52962306a36Sopenharmony_ci		fill_nbits(pdec, 16);
53062306a36Sopenharmony_ci		htable_idx = look_nbits(pdec, 6);
53162306a36Sopenharmony_ci		op = hash_table_ops[htable_idx * 4];
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci		if (op == 2) {
53462306a36Sopenharmony_ci			skip_nbits(pdec, 2);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci		} else if (op == 1) {
53762306a36Sopenharmony_ci			/* 15bits [ xxxx xxxx yyyy 111 ]
53862306a36Sopenharmony_ci			 * yyy => offset in the table8004
53962306a36Sopenharmony_ci			 * xxx => offset in the tabled004 (tree)
54062306a36Sopenharmony_ci			 */
54162306a36Sopenharmony_ci			unsigned int mask, shift;
54262306a36Sopenharmony_ci			unsigned int nbits, col1;
54362306a36Sopenharmony_ci			unsigned int yyyy;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci			skip_nbits(pdec, 3);
54662306a36Sopenharmony_ci			/* offset1 += yyyy */
54762306a36Sopenharmony_ci			__get_nbits(pdec, 4, yyyy);
54862306a36Sopenharmony_ci			offset1 += 1 + yyyy;
54962306a36Sopenharmony_ci			offset1 &= 0x0F;
55062306a36Sopenharmony_ci			nbits = ptable8004[offset1 * 2];
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci			/* col1 = xxxx xxxx */
55362306a36Sopenharmony_ci			__get_nbits(pdec, nbits+1, col1);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci			/* Bit mask table */
55662306a36Sopenharmony_ci			mask = pdec->table_bitpowermask[nbits][col1];
55762306a36Sopenharmony_ci			shift = ptable8004[offset1 * 2 + 1];
55862306a36Sopenharmony_ci			rows = ((mask << shift) + 0x80) & 0xFF;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci			block = pdec->table_subblock[rows];
56162306a36Sopenharmony_ci			for (i = 0; i < 16; i++)
56262306a36Sopenharmony_ci				pdec->temp_colors[i] += block[MulIdx[offset1][i]];
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci		} else {
56562306a36Sopenharmony_ci			/* op == 0
56662306a36Sopenharmony_ci			 * offset1 is coded on 3 bits
56762306a36Sopenharmony_ci			 */
56862306a36Sopenharmony_ci			unsigned int shift;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci			offset1 += hash_table_ops [htable_idx * 4 + 2];
57162306a36Sopenharmony_ci			offset1 &= 0x0F;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci			rows = ptable0004[offset1 + hash_table_ops [htable_idx * 4 + 3]];
57462306a36Sopenharmony_ci			block = pdec->table_subblock[rows];
57562306a36Sopenharmony_ci			for (i = 0; i < 16; i++)
57662306a36Sopenharmony_ci				pdec->temp_colors[i] += block[MulIdx[offset1][i]];
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci			shift = hash_table_ops[htable_idx * 4 + 1];
57962306a36Sopenharmony_ci			skip_nbits(pdec, shift);
58062306a36Sopenharmony_ci		}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	} while (op != 2);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_cistatic void DecompressBand23(struct pwc_dec23_private *pdec,
58762306a36Sopenharmony_ci			     const unsigned char *rawyuv,
58862306a36Sopenharmony_ci			     unsigned char *planar_y,
58962306a36Sopenharmony_ci			     unsigned char *planar_u,
59062306a36Sopenharmony_ci			     unsigned char *planar_v,
59162306a36Sopenharmony_ci			     unsigned int   compressed_image_width,
59262306a36Sopenharmony_ci			     unsigned int   real_image_width)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	int compression_index, nblocks;
59562306a36Sopenharmony_ci	const unsigned char *ptable0004;
59662306a36Sopenharmony_ci	const unsigned char *ptable8004;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	pdec->reservoir = 0;
59962306a36Sopenharmony_ci	pdec->nbits_in_reservoir = 0;
60062306a36Sopenharmony_ci	pdec->stream = rawyuv + 1;	/* The first byte of the stream is skipped */
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	get_nbits(pdec, 4, compression_index);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	/* pass 1: uncompress Y component */
60562306a36Sopenharmony_ci	nblocks = compressed_image_width / 4;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	ptable0004 = pdec->table_0004_pass1[compression_index];
60862306a36Sopenharmony_ci	ptable8004 = pdec->table_8004_pass1[compression_index];
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	/* Each block decode a square of 4x4 */
61162306a36Sopenharmony_ci	while (nblocks) {
61262306a36Sopenharmony_ci		decode_block(pdec, ptable0004, ptable8004);
61362306a36Sopenharmony_ci		copy_image_block_Y(pdec->temp_colors, planar_y, real_image_width, pdec->scalebits);
61462306a36Sopenharmony_ci		planar_y += 4;
61562306a36Sopenharmony_ci		nblocks--;
61662306a36Sopenharmony_ci	}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	/* pass 2: uncompress UV component */
61962306a36Sopenharmony_ci	nblocks = compressed_image_width / 8;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	ptable0004 = pdec->table_0004_pass2[compression_index];
62262306a36Sopenharmony_ci	ptable8004 = pdec->table_8004_pass2[compression_index];
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	/* Each block decode a square of 4x4 */
62562306a36Sopenharmony_ci	while (nblocks) {
62662306a36Sopenharmony_ci		decode_block(pdec, ptable0004, ptable8004);
62762306a36Sopenharmony_ci		copy_image_block_CrCb(pdec->temp_colors, planar_u, real_image_width/2, pdec->scalebits);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci		decode_block(pdec, ptable0004, ptable8004);
63062306a36Sopenharmony_ci		copy_image_block_CrCb(pdec->temp_colors, planar_v, real_image_width/2, pdec->scalebits);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci		planar_v += 8;
63362306a36Sopenharmony_ci		planar_u += 8;
63462306a36Sopenharmony_ci		nblocks -= 2;
63562306a36Sopenharmony_ci	}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci/**
64062306a36Sopenharmony_ci * pwc_dec23_decompress - Uncompress a pwc23 buffer.
64162306a36Sopenharmony_ci * @pdev: pointer to pwc device's internal struct
64262306a36Sopenharmony_ci * @src: raw data
64362306a36Sopenharmony_ci * @dst: image output
64462306a36Sopenharmony_ci */
64562306a36Sopenharmony_civoid pwc_dec23_decompress(struct pwc_device *pdev,
64662306a36Sopenharmony_ci			  const void *src,
64762306a36Sopenharmony_ci			  void *dst)
64862306a36Sopenharmony_ci{
64962306a36Sopenharmony_ci	int bandlines_left, bytes_per_block;
65062306a36Sopenharmony_ci	struct pwc_dec23_private *pdec = &pdev->dec23;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	/* YUV420P image format */
65362306a36Sopenharmony_ci	unsigned char *pout_planar_y;
65462306a36Sopenharmony_ci	unsigned char *pout_planar_u;
65562306a36Sopenharmony_ci	unsigned char *pout_planar_v;
65662306a36Sopenharmony_ci	unsigned int   plane_size;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	mutex_lock(&pdec->lock);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	bandlines_left = pdev->height / 4;
66162306a36Sopenharmony_ci	bytes_per_block = pdev->width * 4;
66262306a36Sopenharmony_ci	plane_size = pdev->height * pdev->width;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	pout_planar_y = dst;
66562306a36Sopenharmony_ci	pout_planar_u = dst + plane_size;
66662306a36Sopenharmony_ci	pout_planar_v = dst + plane_size + plane_size / 4;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	while (bandlines_left--) {
66962306a36Sopenharmony_ci		DecompressBand23(pdec, src,
67062306a36Sopenharmony_ci				 pout_planar_y, pout_planar_u, pout_planar_v,
67162306a36Sopenharmony_ci				 pdev->width, pdev->width);
67262306a36Sopenharmony_ci		src += pdev->vbandlength;
67362306a36Sopenharmony_ci		pout_planar_y += bytes_per_block;
67462306a36Sopenharmony_ci		pout_planar_u += pdev->width;
67562306a36Sopenharmony_ci		pout_planar_v += pdev->width;
67662306a36Sopenharmony_ci	}
67762306a36Sopenharmony_ci	mutex_unlock(&pdec->lock);
67862306a36Sopenharmony_ci}
679