// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2005-2006 Micronas USA Inc.
*/
/*
* This file contains code to generate a firmware image for the GO7007SB
* encoder. Much of the firmware is read verbatim from a file, but some of
* it concerning bitrate control and other things that can be configured at
* run-time are generated dynamically. Note that the format headers
* generated here do not affect the functioning of the encoder; they are
* merely parroted back to the host at the start of each frame.
*/
#include <linux/module.h>
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/firmware.h>
#include <linux/slab.h>
#include <asm /byteorder.h>
#include "go7007-priv.h"
#define GO7007_FW_NAME "go7007/go7007tv.bin"
/* Constants used in the source firmware image to describe code segments */
#define FLAG_MODE_MJPEG (1 )
#define FLAG_MODE_MPEG1 (1 <<1 )
#define FLAG_MODE_MPEG2 (1 <<2 )
#define FLAG_MODE_MPEG4 (1 <<3 )
#define FLAG_MODE_H263 (1 <<4 )
#define FLAG_MODE_ALL (FLAG_MODE_MJPEG | FLAG_MODE_MPEG1 | \
FLAG_MODE_MPEG2 | FLAG_MODE_MPEG4 | \
FLAG_MODE_H263)
#define FLAG_SPECIAL (1 <<8 )
#define SPECIAL_FRM_HEAD 0
#define SPECIAL_BRC_CTRL 1
#define SPECIAL_CONFIG 2
#define SPECIAL_SEQHEAD 3
#define SPECIAL_AV_SYNC 4
#define SPECIAL_FINAL 5
#define SPECIAL_AUDIO 6
#define SPECIAL_MODET 7
/* Little data class for creating MPEG headers bit-by-bit */
struct code_gen {
unsigned char *p; /* destination */
u32 a; /* collects bits at the top of the variable */
int b; /* bit position of most recently-written bit */
int len; /* written out so far */
};
#define CODE_GEN(name, dest) struct code_gen name = { dest, 0 , 32 , 0 }
#define CODE_ADD(name, val, length) do { \
name.b -= (length); \
name.a |= (val) << name.b; \
while (name.b <= 24 ) { \
*name.p = name.a >> 24 ; \
++name.p; \
name.a <<= 8 ; \
name.b += 8 ; \
name.len += 8 ; \
} \
} while (0 )
#define CODE_LENGTH(name) (name.len + (32 - name.b))
/* Tables for creating the bitrate control data */
static const s16 converge_speed_ip[101 ] = {
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 2 ,
2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 3 ,
3 , 3 , 3 , 3 , 3 , 4 , 4 , 4 , 4 , 4 ,
5 , 5 , 5 , 6 , 6 , 6 , 7 , 7 , 8 , 8 ,
9 , 10 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 ,
19 , 20 , 22 , 23 , 25 , 27 , 30 , 32 , 35 , 38 ,
41 , 45 , 49 , 53 , 58 , 63 , 69 , 76 , 83 , 91 ,
100
};
static const s16 converge_speed_ipb[101 ] = {
3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 ,
3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 ,
3 , 3 , 3 , 3 , 3 , 4 , 4 , 4 , 4 , 4 ,
4 , 4 , 4 , 4 , 5 , 5 , 5 , 5 , 5 , 6 ,
6 , 6 , 6 , 7 , 7 , 7 , 7 , 8 , 8 , 9 ,
9 , 9 , 10 , 10 , 11 , 12 , 12 , 13 , 14 , 14 ,
15 , 16 , 17 , 18 , 19 , 20 , 22 , 23 , 25 , 26 ,
28 , 30 , 32 , 34 , 37 , 40 , 42 , 46 , 49 , 53 ,
57 , 61 , 66 , 71 , 77 , 83 , 90 , 97 , 106 , 115 ,
125 , 135 , 147 , 161 , 175 , 191 , 209 , 228 , 249 , 273 ,
300
};
static const s16 LAMBDA_table[4 ][101 ] = {
{ 16 , 16 , 16 , 16 , 17 , 17 , 17 , 18 , 18 , 18 ,
19 , 19 , 19 , 20 , 20 , 20 , 21 , 21 , 22 , 22 ,
22 , 23 , 23 , 24 , 24 , 25 , 25 , 25 , 26 , 26 ,
27 , 27 , 28 , 28 , 29 , 29 , 30 , 31 , 31 , 32 ,
32 , 33 , 33 , 34 , 35 , 35 , 36 , 37 , 37 , 38 ,
39 , 39 , 40 , 41 , 42 , 42 , 43 , 44 , 45 , 46 ,
46 , 47 , 48 , 49 , 50 , 51 , 52 , 53 , 54 , 55 ,
56 , 57 , 58 , 59 , 60 , 61 , 62 , 63 , 64 , 65 ,
67 , 68 , 69 , 70 , 72 , 73 , 74 , 76 , 77 , 78 ,
80 , 81 , 83 , 84 , 86 , 87 , 89 , 90 , 92 , 94 ,
96
},
{
20 , 20 , 20 , 21 , 21 , 21 , 22 , 22 , 23 , 23 ,
23 , 24 , 24 , 25 , 25 , 26 , 26 , 27 , 27 , 28 ,
28 , 29 , 29 , 30 , 30 , 31 , 31 , 32 , 33 , 33 ,
34 , 34 , 35 , 36 , 36 , 37 , 38 , 38 , 39 , 40 ,
40 , 41 , 42 , 43 , 43 , 44 , 45 , 46 , 47 , 48 ,
48 , 49 , 50 , 51 , 52 , 53 , 54 , 55 , 56 , 57 ,
58 , 59 , 60 , 61 , 62 , 64 , 65 , 66 , 67 , 68 ,
70 , 71 , 72 , 73 , 75 , 76 , 78 , 79 , 80 , 82 ,
83 , 85 , 86 , 88 , 90 , 91 , 93 , 95 , 96 , 98 ,
100 , 102 , 103 , 105 , 107 , 109 , 111 , 113 , 115 , 117 ,
120
},
{
24 , 24 , 24 , 25 , 25 , 26 , 26 , 27 , 27 , 28 ,
28 , 29 , 29 , 30 , 30 , 31 , 31 , 32 , 33 , 33 ,
34 , 34 , 35 , 36 , 36 , 37 , 38 , 38 , 39 , 40 ,
41 , 41 , 42 , 43 , 44 , 44 , 45 , 46 , 47 , 48 ,
49 , 50 , 50 , 51 , 52 , 53 , 54 , 55 , 56 , 57 ,
58 , 59 , 60 , 62 , 63 , 64 , 65 , 66 , 67 , 69 ,
70 , 71 , 72 , 74 , 75 , 76 , 78 , 79 , 81 , 82 ,
84 , 85 , 87 , 88 , 90 , 92 , 93 , 95 , 97 , 98 ,
100 , 102 , 104 , 106 , 108 , 110 , 112 , 114 , 116 , 118 ,
120 , 122 , 124 , 127 , 129 , 131 , 134 , 136 , 138 , 141 ,
144
},
{
32 , 32 , 33 , 33 , 34 , 34 , 35 , 36 , 36 , 37 ,
38 , 38 , 39 , 40 , 41 , 41 , 42 , 43 , 44 , 44 ,
45 , 46 , 47 , 48 , 49 , 50 , 50 , 51 , 52 , 53 ,
54 , 55 , 56 , 57 , 58 , 59 , 60 , 62 , 63 , 64 ,
65 , 66 , 67 , 69 , 70 , 71 , 72 , 74 , 75 , 76 ,
78 , 79 , 81 , 82 , 84 , 85 , 87 , 88 , 90 , 92 ,
93 , 95 , 97 , 98 , 100 , 102 , 104 , 106 , 108 , 110 ,
112 , 114 , 116 , 118 , 120 , 122 , 124 , 127 , 129 , 131 ,
134 , 136 , 139 , 141 , 144 , 146 , 149 , 152 , 154 , 157 ,
160 , 163 , 166 , 169 , 172 , 175 , 178 , 181 , 185 , 188 ,
192
}
};
/* MPEG blank frame generation tables */
enum mpeg_frame_type {
PFRAME,
BFRAME_PRE,
BFRAME_POST,
BFRAME_BIDIR,
BFRAME_EMPTY
};
static const u32 addrinctab[33 ][2 ] = {
{ 0 x01, 1 }, { 0 x03, 3 }, { 0 x02, 3 }, { 0 x03, 4 },
{ 0 x02, 4 }, { 0 x03, 5 }, { 0 x02, 5 }, { 0 x07, 7 },
{ 0 x06, 7 }, { 0 x0b, 8 }, { 0 x0a, 8 }, { 0 x09, 8 },
{ 0 x08, 8 }, { 0 x07, 8 }, { 0 x06, 8 }, { 0 x17, 10 },
{ 0 x16, 10 }, { 0 x15, 10 }, { 0 x14, 10 }, { 0 x13, 10 },
{ 0 x12, 10 }, { 0 x23, 11 }, { 0 x22, 11 }, { 0 x21, 11 },
{ 0 x20, 11 }, { 0 x1f, 11 }, { 0 x1e, 11 }, { 0 x1d, 11 },
{ 0 x1c, 11 }, { 0 x1b, 11 }, { 0 x1a, 11 }, { 0 x19, 11 },
{ 0 x18, 11 }
};
/* Standard JPEG tables */
static const u8 default_intra_quant_table[] = {
8 , 16 , 19 , 22 , 26 , 27 , 29 , 34 ,
16 , 16 , 22 , 24 , 27 , 29 , 34 , 37 ,
19 , 22 , 26 , 27 , 29 , 34 , 34 , 38 ,
22 , 22 , 26 , 27 , 29 , 34 , 37 , 40 ,
22 , 26 , 27 , 29 , 32 , 35 , 40 , 48 ,
26 , 27 , 29 , 32 , 35 , 40 , 48 , 58 ,
26 , 27 , 29 , 34 , 38 , 46 , 56 , 69 ,
27 , 29 , 35 , 38 , 46 , 56 , 69 , 83
};
static const u8 bits_dc_luminance[] = {
0 , 0 , 1 , 5 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0
};
static const u8 val_dc_luminance[] = {
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11
};
static const u8 bits_dc_chrominance[] = {
0 , 0 , 3 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0
};
static const u8 val_dc_chrominance[] = {
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11
};
static const u8 bits_ac_luminance[] = {
0 , 0 , 2 , 1 , 3 , 3 , 2 , 4 , 3 , 5 , 5 , 4 , 4 , 0 , 0 , 1 , 0 x7d
};
static const u8 val_ac_luminance[] = {
0 x01, 0 x02, 0 x03, 0 x00, 0 x04, 0 x11, 0 x05, 0 x12,
0 x21, 0 x31, 0 x41, 0 x06, 0 x13, 0 x51, 0 x61, 0 x07,
0 x22, 0 x71, 0 x14, 0 x32, 0 x81, 0 x91, 0 xa1, 0 x08,
0 x23, 0 x42, 0 xb1, 0 xc1, 0 x15, 0 x52, 0 xd1, 0 xf0,
0 x24, 0 x33, 0 x62, 0 x72, 0 x82, 0 x09, 0 x0a, 0 x16,
0 x17, 0 x18, 0 x19, 0 x1a, 0 x25, 0 x26, 0 x27, 0 x28,
0 x29, 0 x2a, 0 x34, 0 x35, 0 x36, 0 x37, 0 x38, 0 x39,
0 x3a, 0 x43, 0 x44, 0 x45, 0 x46, 0 x47, 0 x48, 0 x49,
0 x4a, 0 x53, 0 x54, 0 x55, 0 x56, 0 x57, 0 x58, 0 x59,
0 x5a, 0 x63, 0 x64, 0 x65, 0 x66, 0 x67, 0 x68, 0 x69,
0 x6a, 0 x73, 0 x74, 0 x75, 0 x76, 0 x77, 0 x78, 0 x79,
0 x7a, 0 x83, 0 x84, 0 x85, 0 x86, 0 x87, 0 x88, 0 x89,
0 x8a, 0 x92, 0 x93, 0 x94, 0 x95, 0 x96, 0 x97, 0 x98,
0 x99, 0 x9a, 0 xa2, 0 xa3, 0 xa4, 0 xa5, 0 xa6, 0 xa7,
0 xa8, 0 xa9, 0 xaa, 0 xb2, 0 xb3, 0 xb4, 0 xb5, 0 xb6,
0 xb7, 0 xb8, 0 xb9, 0 xba, 0 xc2, 0 xc3, 0 xc4, 0 xc5,
0 xc6, 0 xc7, 0 xc8, 0 xc9, 0 xca, 0 xd2, 0 xd3, 0 xd4,
0 xd5, 0 xd6, 0 xd7, 0 xd8, 0 xd9, 0 xda, 0 xe1, 0 xe2,
0 xe3, 0 xe4, 0 xe5, 0 xe6, 0 xe7, 0 xe8, 0 xe9, 0 xea,
0 xf1, 0 xf2, 0 xf3, 0 xf4, 0 xf5, 0 xf6, 0 xf7, 0 xf8,
0 xf9, 0 xfa
};
static const u8 bits_ac_chrominance[] = {
0 , 0 , 2 , 1 , 2 , 4 , 4 , 3 , 4 , 7 , 5 , 4 , 4 , 0 , 1 , 2 , 0 x77
};
static const u8 val_ac_chrominance[] = {
0 x00, 0 x01, 0 x02, 0 x03, 0 x11, 0 x04, 0 x05, 0 x21,
0 x31, 0 x06, 0 x12, 0 x41, 0 x51, 0 x07, 0 x61, 0 x71,
0 x13, 0 x22, 0 x32, 0 x81, 0 x08, 0 x14, 0 x42, 0 x91,
0 xa1, 0 xb1, 0 xc1, 0 x09, 0 x23, 0 x33, 0 x52, 0 xf0,
0 x15, 0 x62, 0 x72, 0 xd1, 0 x0a, 0 x16, 0 x24, 0 x34,
0 xe1, 0 x25, 0 xf1, 0 x17, 0 x18, 0 x19, 0 x1a, 0 x26,
0 x27, 0 x28, 0 x29, 0 x2a, 0 x35, 0 x36, 0 x37, 0 x38,
0 x39, 0 x3a, 0 x43, 0 x44, 0 x45, 0 x46, 0 x47, 0 x48,
0 x49, 0 x4a, 0 x53, 0 x54, 0 x55, 0 x56, 0 x57, 0 x58,
0 x59, 0 x5a, 0 x63, 0 x64, 0 x65, 0 x66, 0 x67, 0 x68,
0 x69, 0 x6a, 0 x73, 0 x74, 0 x75, 0 x76, 0 x77, 0 x78,
0 x79, 0 x7a, 0 x82, 0 x83, 0 x84, 0 x85, 0 x86, 0 x87,
0 x88, 0 x89, 0 x8a, 0 x92, 0 x93, 0 x94, 0 x95, 0 x96,
0 x97, 0 x98, 0 x99, 0 x9a, 0 xa2, 0 xa3, 0 xa4, 0 xa5,
0 xa6, 0 xa7, 0 xa8, 0 xa9, 0 xaa, 0 xb2, 0 xb3, 0 xb4,
0 xb5, 0 xb6, 0 xb7, 0 xb8, 0 xb9, 0 xba, 0 xc2, 0 xc3,
0 xc4, 0 xc5, 0 xc6, 0 xc7, 0 xc8, 0 xc9, 0 xca, 0 xd2,
0 xd3, 0 xd4, 0 xd5, 0 xd6, 0 xd7, 0 xd8, 0 xd9, 0 xda,
0 xe2, 0 xe3, 0 xe4, 0 xe5, 0 xe6, 0 xe7, 0 xe8, 0 xe9,
0 xea, 0 xf2, 0 xf3, 0 xf4, 0 xf5, 0 xf6, 0 xf7, 0 xf8,
0 xf9, 0 xfa
};
/* Zig-zag mapping for quant table
*
* OK, let's do this mapping on the actual table above so it doesn't have
* to be done on the fly.
*/
static const int zz[64 ] = {
0 , 1 , 8 , 16 , 9 , 2 , 3 , 10 , 17 , 24 , 32 , 25 , 18 , 11 , 4 , 5 ,
12 , 19 , 26 , 33 , 40 , 48 , 41 , 34 , 27 , 20 , 13 , 6 , 7 , 14 , 21 , 28 ,
35 , 42 , 49 , 56 , 57 , 50 , 43 , 36 , 29 , 22 , 15 , 23 , 30 , 37 , 44 , 51 ,
58 , 59 , 52 , 45 , 38 , 31 , 39 , 46 , 53 , 60 , 61 , 54 , 47 , 55 , 62 , 63
};
static int copy_packages(__le16 *dest, u16 *src, int pkg_cnt, int space)
{
int i, cnt = pkg_cnt * 32 ;
if (space < cnt)
return -1 ;
for (i = 0 ; i < cnt; ++i)
dest[i] = cpu_to_le16p(src + i);
return cnt;
}
static int mjpeg_frame_header(struct go7007 *go, unsigned char *buf, int q)
{
int i, p = 0 ;
buf[p++] = 0 xff;
buf[p++] = 0 xd8;
buf[p++] = 0 xff;
buf[p++] = 0 xdb;
buf[p++] = 0 ;
buf[p++] = 2 + 65 ;
buf[p++] = 0 ;
buf[p++] = default_intra_quant_table[0 ];
for (i = 1 ; i < 64 ; ++i)
/* buf[p++] = (default_intra_quant_table[i] * q) >> 3; */
buf[p++] = (default_intra_quant_table[zz[i]] * q) >> 3 ;
buf[p++] = 0 xff;
buf[p++] = 0 xc0;
buf[p++] = 0 ;
buf[p++] = 17 ;
buf[p++] = 8 ;
buf[p++] = go->height >> 8 ;
buf[p++] = go->height & 0 xff;
buf[p++] = go->width >> 8 ;
buf[p++] = go->width & 0 xff;
buf[p++] = 3 ;
buf[p++] = 1 ;
buf[p++] = 0 x22;
buf[p++] = 0 ;
buf[p++] = 2 ;
buf[p++] = 0 x11;
buf[p++] = 0 ;
buf[p++] = 3 ;
buf[p++] = 0 x11;
buf[p++] = 0 ;
buf[p++] = 0 xff;
buf[p++] = 0 xc4;
buf[p++] = 418 >> 8 ;
buf[p++] = 418 & 0 xff;
buf[p++] = 0 x00;
memcpy(buf + p, bits_dc_luminance + 1 , 16 );
p += 16 ;
memcpy(buf + p, val_dc_luminance, sizeof (val_dc_luminance));
p += sizeof (val_dc_luminance);
buf[p++] = 0 x01;
memcpy(buf + p, bits_dc_chrominance + 1 , 16 );
p += 16 ;
memcpy(buf + p, val_dc_chrominance, sizeof (val_dc_chrominance));
p += sizeof (val_dc_chrominance);
buf[p++] = 0 x10;
memcpy(buf + p, bits_ac_luminance + 1 , 16 );
p += 16 ;
memcpy(buf + p, val_ac_luminance, sizeof (val_ac_luminance));
p += sizeof (val_ac_luminance);
buf[p++] = 0 x11;
memcpy(buf + p, bits_ac_chrominance + 1 , 16 );
p += 16 ;
memcpy(buf + p, val_ac_chrominance, sizeof (val_ac_chrominance));
p += sizeof (val_ac_chrominance);
buf[p++] = 0 xff;
buf[p++] = 0 xda;
buf[p++] = 0 ;
buf[p++] = 12 ;
buf[p++] = 3 ;
buf[p++] = 1 ;
buf[p++] = 0 x00;
buf[p++] = 2 ;
buf[p++] = 0 x11;
buf[p++] = 3 ;
buf[p++] = 0 x11;
buf[p++] = 0 ;
buf[p++] = 63 ;
buf[p++] = 0 ;
return p;
}
static int gen_mjpeghdr_to_package(struct go7007 *go, __le16 *code, int space)
{
u8 *buf;
u16 mem = 0 x3e00;
unsigned int addr = 0 x19;
int size = 0 , i, off = 0 , chunk;
buf = kzalloc(4096 , GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
for (i = 1 ; i < 32 ; ++i) {
mjpeg_frame_header(go, buf + size, i);
size += 80 ;
}
chunk = mjpeg_frame_header(go, buf + size, 1 );
memmove(buf + size, buf + size + 80 , chunk - 80 );
size += chunk - 80 ;
for (i = 0 ; i < size; i += chunk * 2 ) {
if (space - off < 32 ) {
off = -1 ;
goto done;
}
code[off + 1 ] = __cpu_to_le16(0 x8000 | mem);
chunk = 28 ;
if (mem + chunk > 0 x4000)
chunk = 0 x4000 - mem;
if (i + 2 * chunk > size)
chunk = (size - i) / 2 ;
if (chunk < 28 ) {
code[off] = __cpu_to_le16(0 x4000 | chunk);
code[off + 31 ] = __cpu_to_le16(addr++);
mem = 0 x3e00;
} else {
code[off] = __cpu_to_le16(0 x1000 | 28 );
code[off + 31 ] = 0 ;
mem += 28 ;
}
memcpy(&code[off + 2 ], buf + i, chunk * 2 );
off += 32 ;
}
done:
kfree(buf);
return off;
}
static int mpeg1_frame_header(struct go7007 *go, unsigned char *buf,
int modulo, int pict_struct, enum mpeg_frame_type frame)
{
int i, j, mb_code, mb_len;
int rows = go->interlace_coding ? go->height / 32 : go->height / 16 ;
CODE_GEN(c, buf + 6 );
switch (frame) {
case PFRAME:
mb_code = 0 x1;
mb_len = 3 ;
break ;
case BFRAME_PRE:
mb_code = 0 x2;
mb_len = 4 ;
break ;
case BFRAME_POST:
mb_code = 0 x2;
mb_len = 3 ;
break ;
case BFRAME_BIDIR:
mb_code = 0 x2;
mb_len = 2 ;
break ;
default : /* keep the compiler happy */
mb_code = mb_len = 0 ;
break ;
}
CODE_ADD(c, frame == PFRAME ? 0 x2 : 0 x3, 13 );
CODE_ADD(c, 0 xffff, 16 );
CODE_ADD(c, go->format == V4L2_PIX_FMT_MPEG2 ? 0 x7 : 0 x4, 4 );
if (frame != PFRAME)
CODE_ADD(c, go->format == V4L2_PIX_FMT_MPEG2 ? 0 x7 : 0 x4, 4 );
else
CODE_ADD(c, 0 , 4 ); /* Is this supposed to be here?? */
CODE_ADD(c, 0 , 3 ); /* What is this?? */
/* Byte-align with zeros */
j = 8 - (CODE_LENGTH(c) % 8 );
if (j != 8 )
CODE_ADD(c, 0 , j);
if (go->format == V4L2_PIX_FMT_MPEG2) {
CODE_ADD(c, 0 x1, 24 );
CODE_ADD(c, 0 xb5, 8 );
CODE_ADD(c, 0 x844, 12 );
CODE_ADD(c, frame == PFRAME ? 0 xff : 0 x44, 8 );
if (go->interlace_coding) {
CODE_ADD(c, pict_struct, 4 );
if (go->dvd_mode)
CODE_ADD(c, 0 x000, 11 );
else
CODE_ADD(c, 0 x200, 11 );
} else {
CODE_ADD(c, 0 x3, 4 );
CODE_ADD(c, 0 x20c, 11 );
}
/* Byte-align with zeros */
j = 8 - (CODE_LENGTH(c) % 8 );
if (j != 8 )
CODE_ADD(c, 0 , j);
}
for (i = 0 ; i < rows; ++i) {
CODE_ADD(c, 1 , 24 );
CODE_ADD(c, i + 1 , 8 );
CODE_ADD(c, 0 x2, 6 );
CODE_ADD(c, 0 x1, 1 );
CODE_ADD(c, mb_code, mb_len);
if (go->interlace_coding) {
CODE_ADD(c, 0 x1, 2 );
CODE_ADD(c, pict_struct == 1 ? 0 x0 : 0 x1, 1 );
}
if (frame == BFRAME_BIDIR) {
CODE_ADD(c, 0 x3, 2 );
if (go->interlace_coding)
CODE_ADD(c, pict_struct == 1 ? 0 x0 : 0 x1, 1 );
}
CODE_ADD(c, 0 x3, 2 );
for (j = (go->width >> 4 ) - 2 ; j >= 33 ; j -= 33 )
CODE_ADD(c, 0 x8, 11 );
CODE_ADD(c, addrinctab[j][0 ], addrinctab[j][1 ]);
CODE_ADD(c, mb_code, mb_len);
if (go->interlace_coding) {
CODE_ADD(c, 0 x1, 2 );
CODE_ADD(c, pict_struct == 1 ? 0 x0 : 0 x1, 1 );
}
if (frame == BFRAME_BIDIR) {
CODE_ADD(c, 0 x3, 2 );
if (go->interlace_coding)
CODE_ADD(c, pict_struct == 1 ? 0 x0 : 0 x1, 1 );
}
CODE_ADD(c, 0 x3, 2 );
/* Byte-align with zeros */
j = 8 - (CODE_LENGTH(c) % 8 );
if (j != 8 )
CODE_ADD(c, 0 , j);
}
i = CODE_LENGTH(c) + 4 * 8 ;
buf[2 ] = 0 x00;
buf[3 ] = 0 x00;
buf[4 ] = 0 x01;
buf[5 ] = 0 x00;
return i;
}
static int mpeg1_sequence_header(struct go7007 *go, unsigned char *buf, int ext)
{
int i, aspect_ratio, picture_rate;
CODE_GEN(c, buf + 6 );
if (go->format == V4L2_PIX_FMT_MPEG1) {
switch (go->aspect_ratio) {
case GO7007_RATIO_4_3:
aspect_ratio = go->standard == GO7007_STD_NTSC ? 3 : 2 ;
break ;
case GO7007_RATIO_16_9:
aspect_ratio = go->standard == GO7007_STD_NTSC ? 5 : 4 ;
break ;
default :
aspect_ratio = 1 ;
break ;
}
} else {
switch (go->aspect_ratio) {
case GO7007_RATIO_4_3:
aspect_ratio = 2 ;
break ;
case GO7007_RATIO_16_9:
aspect_ratio = 3 ;
break ;
default :
aspect_ratio = 1 ;
break ;
}
}
switch (go->sensor_framerate) {
case 24000 :
picture_rate = 1 ;
break ;
case 24024 :
picture_rate = 2 ;
break ;
case 25025 :
picture_rate = go->interlace_coding ? 6 : 3 ;
break ;
case 30000 :
picture_rate = go->interlace_coding ? 7 : 4 ;
break ;
case 30030 :
picture_rate = go->interlace_coding ? 8 : 5 ;
break ;
default :
picture_rate = 5 ; /* 30 fps seems like a reasonable default */
break ;
}
CODE_ADD(c, go->width, 12 );
CODE_ADD(c, go->height, 12 );
CODE_ADD(c, aspect_ratio, 4 );
CODE_ADD(c, picture_rate, 4 );
CODE_ADD(c, go->format == V4L2_PIX_FMT_MPEG2 ? 20000 : 0 x3ffff, 18 );
CODE_ADD(c, 1 , 1 );
CODE_ADD(c, go->format == V4L2_PIX_FMT_MPEG2 ? 112 : 20 , 10 );
CODE_ADD(c, 0 , 3 );
/* Byte-align with zeros */
i = 8 - (CODE_LENGTH(c) % 8 );
if (i != 8 )
CODE_ADD(c, 0 , i);
if (go->format == V4L2_PIX_FMT_MPEG2) {
CODE_ADD(c, 0 x1, 24 );
CODE_ADD(c, 0 xb5, 8 );
CODE_ADD(c, 0 x148, 12 );
if (go->interlace_coding)
CODE_ADD(c, 0 x20001, 20 );
else
CODE_ADD(c, 0 xa0001, 20 );
CODE_ADD(c, 0 , 16 );
/* Byte-align with zeros */
i = 8 - (CODE_LENGTH(c) % 8 );
if (i != 8 )
CODE_ADD(c, 0 , i);
if (ext) {
CODE_ADD(c, 0 x1, 24 );
CODE_ADD(c, 0 xb52, 12 );
CODE_ADD(c, go->standard == GO7007_STD_NTSC ? 2 : 1 , 3 );
CODE_ADD(c, 0 x105, 9 );
CODE_ADD(c, 0 x505, 16 );
CODE_ADD(c, go->width, 14 );
CODE_ADD(c, 1 , 1 );
CODE_ADD(c, go->height, 14 );
/* Byte-align with zeros */
i = 8 - (CODE_LENGTH(c) % 8 );
if (i != 8 )
CODE_ADD(c, 0 , i);
}
}
i = CODE_LENGTH(c) + 4 * 8 ;
buf[0 ] = i & 0 xff;
buf[1 ] = i >> 8 ;
buf[2 ] = 0 x00;
buf[3 ] = 0 x00;
buf[4 ] = 0 x01;
buf[5 ] = 0 xb3;
return i;
}
static int gen_mpeg1hdr_to_package(struct go7007 *go,
__le16 *code, int space, int *framelen)
{
u8 *buf;
u16 mem = 0 x3e00;
unsigned int addr = 0 x19;
int i, off = 0 , chunk;
buf = kzalloc(5120 , GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
framelen[0 ] = mpeg1_frame_header(go, buf, 0 , 1 , PFRAME);
if (go->interlace_coding)
framelen[0 ] += mpeg1_frame_header(go, buf + framelen[0 ] / 8 ,
0 , 2 , PFRAME);
buf[0 ] = framelen[0 ] & 0 xff;
buf[1 ] = framelen[0 ] >> 8 ;
i = 368 ;
framelen[1 ] = mpeg1_frame_header(go, buf + i, 0 , 1 , BFRAME_PRE);
if (go->interlace_coding)
framelen[1 ] += mpeg1_frame_header(go, buf + i + framelen[1 ] / 8 ,
0 , 2 , BFRAME_PRE);
buf[i] = framelen[1 ] & 0 xff;
buf[i + 1 ] = framelen[1 ] >> 8 ;
i += 1632 ;
framelen[2 ] = mpeg1_frame_header(go, buf + i, 0 , 1 , BFRAME_POST);
if (go->interlace_coding)
framelen[2 ] += mpeg1_frame_header(go, buf + i + framelen[2 ] / 8 ,
0 , 2 , BFRAME_POST);
buf[i] = framelen[2 ] & 0 xff;
buf[i + 1 ] = framelen[2 ] >> 8 ;
i += 1432 ;
framelen[3 ] = mpeg1_frame_header(go, buf + i, 0 , 1 , BFRAME_BIDIR);
if (go->interlace_coding)
framelen[3 ] += mpeg1_frame_header(go, buf + i + framelen[3 ] / 8 ,
0 , 2 , BFRAME_BIDIR);
buf[i] = framelen[3 ] & 0 xff;
buf[i + 1 ] = framelen[3 ] >> 8 ;
i += 1632 + 16 ;
mpeg1_sequence_header(go, buf + i, 0 );
i += 40 ;
for (i = 0 ; i < 5120 ; i += chunk * 2 ) {
if (space - off < 32 ) {
off = -1 ;
goto done;
}
code[off + 1 ] = __cpu_to_le16(0 x8000 | mem);
chunk = 28 ;
if (mem + chunk > 0 x4000)
chunk = 0 x4000 - mem;
if (i + 2 * chunk > 5120 )
chunk = (5120 - i) / 2 ;
if (chunk < 28 ) {
code[off] = __cpu_to_le16(0 x4000 | chunk);
code[off + 31 ] = __cpu_to_le16(addr);
if (mem + chunk == 0 x4000) {
mem = 0 x3e00;
++addr;
}
} else {
code[off] = __cpu_to_le16(0 x1000 | 28 );
code[off + 31 ] = 0 ;
mem += 28 ;
}
memcpy(&code[off + 2 ], buf + i, chunk * 2 );
off += 32 ;
}
done:
kfree(buf);
return off;
}
static int vti_bitlen(struct go7007 *go)
{
unsigned int i, max_time_incr = go->sensor_framerate / go->fps_scale;
for (i = 31 ; (max_time_incr & ((1 << i) - 1 )) == max_time_incr; --i)
;
return i + 1 ;
}
static int mpeg4_frame_header(struct go7007 *go, unsigned char *buf,
int modulo, enum mpeg_frame_type frame)
{
int i;
CODE_GEN(c, buf + 6 );
int mb_count = (go->width >> 4 ) * (go->height >> 4 );
CODE_ADD(c, frame == PFRAME ? 0 x1 : 0 x2, 2 );
if (modulo)
CODE_ADD(c, 0 x1, 1 );
CODE_ADD(c, 0 x1, 2 );
CODE_ADD(c, 0 , vti_bitlen(go));
CODE_ADD(c, 0 x3, 2 );
if (frame == PFRAME)
CODE_ADD(c, 0 , 1 );
CODE_ADD(c, 0 xc, 11 );
if (frame != PFRAME)
CODE_ADD(c, 0 x4, 3 );
if (frame != BFRAME_EMPTY) {
for (i = 0 ; i < mb_count; ++i) {
switch (frame) {
case PFRAME:
CODE_ADD(c, 0 x1, 1 );
break ;
case BFRAME_PRE:
CODE_ADD(c, 0 x47, 8 );
break ;
case BFRAME_POST:
CODE_ADD(c, 0 x27, 7 );
break ;
case BFRAME_BIDIR:
CODE_ADD(c, 0 x5f, 8 );
break ;
case BFRAME_EMPTY: /* keep compiler quiet */
break ;
}
}
}
/* Byte-align with a zero followed by ones */
i = 8 - (CODE_LENGTH(c) % 8 );
CODE_ADD(c, 0 , 1 );
CODE_ADD(c, (1 << (i - 1 )) - 1 , i - 1 );
i = CODE_LENGTH(c) + 4 * 8 ;
buf[0 ] = i & 0 xff;
buf[1 ] = i >> 8 ;
buf[2 ] = 0 x00;
buf[3 ] = 0 x00;
buf[4 ] = 0 x01;
buf[5 ] = 0 xb6;
return i;
}
static int mpeg4_sequence_header(struct go7007 *go, unsigned char *buf, int ext)
{
const unsigned char head[] = { 0 x00, 0 x00, 0 x01, 0 xb0, go->pali,
0 x00, 0 x00, 0 x01, 0 xb5, 0 x09,
0 x00, 0 x00, 0 x01, 0 x00,
0 x00, 0 x00, 0 x01, 0 x20, };
int i, aspect_ratio;
int fps = go->sensor_framerate / go->fps_scale;
CODE_GEN(c, buf + 2 + sizeof (head));
switch (go->aspect_ratio) {
case GO7007_RATIO_4_3:
aspect_ratio = go->standard == GO7007_STD_NTSC ? 3 : 2 ;
break ;
case GO7007_RATIO_16_9:
aspect_ratio = go->standard == GO7007_STD_NTSC ? 5 : 4 ;
break ;
default :
aspect_ratio = 1 ;
break ;
}
memcpy(buf + 2 , head, sizeof (head));
CODE_ADD(c, 0 x191, 17 );
CODE_ADD(c, aspect_ratio, 4 );
CODE_ADD(c, 0 x1, 4 );
CODE_ADD(c, fps, 16 );
CODE_ADD(c, 0 x3, 2 );
CODE_ADD(c, 1001 , vti_bitlen(go));
CODE_ADD(c, 1 , 1 );
CODE_ADD(c, go->width, 13 );
CODE_ADD(c, 1 , 1 );
CODE_ADD(c, go->height, 13 );
CODE_ADD(c, 0 x2830, 14 );
/* Byte-align */
i = 8 - (CODE_LENGTH(c) % 8 );
CODE_ADD(c, 0 , 1 );
CODE_ADD(c, (1 << (i - 1 )) - 1 , i - 1 );
i = CODE_LENGTH(c) + sizeof (head) * 8 ;
buf[0 ] = i & 0 xff;
buf[1 ] = i >> 8 ;
return i;
}
static int gen_mpeg4hdr_to_package(struct go7007 *go,
__le16 *code, int space, int *framelen)
{
u8 *buf;
u16 mem = 0 x3e00;
unsigned int addr = 0 x19;
int i, off = 0 , chunk;
buf = kzalloc(5120 , GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
framelen[0 ] = mpeg4_frame_header(go, buf, 0 , PFRAME);
i = 368 ;
framelen[1 ] = mpeg4_frame_header(go, buf + i, 0 , BFRAME_PRE);
i += 1632 ;
framelen[2 ] = mpeg4_frame_header(go, buf + i, 0 , BFRAME_POST);
i += 1432 ;
framelen[3 ] = mpeg4_frame_header(go, buf + i, 0 , BFRAME_BIDIR);
i += 1632 ;
mpeg4_frame_header(go, buf + i, 0 , BFRAME_EMPTY);
i += 16 ;
mpeg4_sequence_header(go, buf + i, 0 );
i += 40 ;
for (i = 0 ; i < 5120 ; i += chunk * 2 ) {
if (space - off < 32 ) {
off = -1 ;
goto done;
}
code[off + 1 ] = __cpu_to_le16(0 x8000 | mem);
chunk = 28 ;
if (mem + chunk > 0 x4000)
chunk = 0 x4000 - mem;
if (i + 2 * chunk > 5120 )
chunk = (5120 - i) / 2 ;
if (chunk < 28 ) {
code[off] = __cpu_to_le16(0 x4000 | chunk);
code[off + 31 ] = __cpu_to_le16(addr);
if (mem + chunk == 0 x4000) {
mem = 0 x3e00;
++addr;
}
} else {
code[off] = __cpu_to_le16(0 x1000 | 28 );
code[off + 31 ] = 0 ;
mem += 28 ;
}
memcpy(&code[off + 2 ], buf + i, chunk * 2 );
off += 32 ;
}
mem = 0 x3e00;
addr = go->ipb ? 0 x14f9 : 0 x0af9;
memset(buf, 0 , 5120 );
framelen[4 ] = mpeg4_frame_header(go, buf, 1 , PFRAME);
i = 368 ;
framelen[5 ] = mpeg4_frame_header(go, buf + i, 1 , BFRAME_PRE);
i += 1632 ;
framelen[6 ] = mpeg4_frame_header(go, buf + i, 1 , BFRAME_POST);
i += 1432 ;
framelen[7 ] = mpeg4_frame_header(go, buf + i, 1 , BFRAME_BIDIR);
i += 1632 ;
mpeg4_frame_header(go, buf + i, 1 , BFRAME_EMPTY);
i += 16 ;
for (i = 0 ; i < 5120 ; i += chunk * 2 ) {
if (space - off < 32 ) {
off = -1 ;
goto done;
}
code[off + 1 ] = __cpu_to_le16(0 x8000 | mem);
chunk = 28 ;
if (mem + chunk > 0 x4000)
chunk = 0 x4000 - mem;
if (i + 2 * chunk > 5120 )
chunk = (5120 - i) / 2 ;
if (chunk < 28 ) {
code[off] = __cpu_to_le16(0 x4000 | chunk);
code[off + 31 ] = __cpu_to_le16(addr);
if (mem + chunk == 0 x4000) {
mem = 0 x3e00;
++addr;
}
} else {
code[off] = __cpu_to_le16(0 x1000 | 28 );
code[off + 31 ] = 0 ;
mem += 28 ;
}
memcpy(&code[off + 2 ], buf + i, chunk * 2 );
off += 32 ;
}
done:
kfree(buf);
return off;
}
static int brctrl_to_package(struct go7007 *go,
__le16 *code, int space, int *framelen)
{
int converge_speed = 0 ;
int lambda = (go->format == V4L2_PIX_FMT_MJPEG || go->dvd_mode) ?
100 : 0 ;
int peak_rate = 6 * go->bitrate / 5 ;
int vbv_buffer = go->format == V4L2_PIX_FMT_MJPEG ?
go->bitrate :
(go->dvd_mode ? 900000 : peak_rate);
int fps = go->sensor_framerate / go->fps_scale;
int q = 0 ;
/* Bizarre math below depends on rounding errors in division */
u32 sgop_expt_addr = go->bitrate / 32 * (go->ipb ? 3 : 1 ) * 1001 / fps;
u32 sgop_peak_addr = peak_rate / 32 * 1001 / fps;
u32 total_expt_addr = go->bitrate / 32 * 1000 / fps * (fps / 1000 );
u32 vbv_alert_addr = vbv_buffer * 3 / (4 * 32 );
u32 cplx[] = {
q > 0 ? sgop_expt_addr * q :
2 * go->width * go->height * (go->ipb ? 6 : 4 ) / 32 ,
q > 0 ? sgop_expt_addr * q :
2 * go->width * go->height * (go->ipb ? 6 : 4 ) / 32 ,
q > 0 ? sgop_expt_addr * q :
2 * go->width * go->height * (go->ipb ? 6 : 4 ) / 32 ,
q > 0 ? sgop_expt_addr * q :
2 * go->width * go->height * (go->ipb ? 6 : 4 ) / 32 ,
};
u32 calc_q = q > 0 ? q : cplx[0 ] / sgop_expt_addr;
u16 pack [] = {
0 x200e, 0 x0000,
0 xBF20, go->ipb ? converge_speed_ipb[converge_speed]
: converge_speed_ip[converge_speed],
0 xBF21, go->ipb ? 2 : 0 ,
0 xBF22, go->ipb ? LAMBDA_table[0 ][lambda / 2 + 50 ]
: 32767 ,
0 xBF23, go->ipb ? LAMBDA_table[1 ][lambda] : 32767 ,
0 xBF24, 32767 ,
0 xBF25, lambda > 99 ? 32767 : LAMBDA_table[3 ][lambda],
0 xBF26, sgop_expt_addr & 0 x0000FFFF,
0 xBF27, sgop_expt_addr >> 16 ,
0 xBF28, sgop_peak_addr & 0 x0000FFFF,
0 xBF29, sgop_peak_addr >> 16 ,
0 xBF2A, vbv_alert_addr & 0 x0000FFFF,
0 xBF2B, vbv_alert_addr >> 16 ,
0 xBF2C, 0 ,
0 xBF2D, 0 ,
0 , 0 ,
0 x200e, 0 x0000,
0 xBF2E, vbv_alert_addr & 0 x0000FFFF,
0 xBF2F, vbv_alert_addr >> 16 ,
0 xBF30, cplx[0 ] & 0 x0000FFFF,
0 xBF31, cplx[0 ] >> 16 ,
0 xBF32, cplx[1 ] & 0 x0000FFFF,
0 xBF33, cplx[1 ] >> 16 ,
0 xBF34, cplx[2 ] & 0 x0000FFFF,
0 xBF35, cplx[2 ] >> 16 ,
0 xBF36, cplx[3 ] & 0 x0000FFFF,
0 xBF37, cplx[3 ] >> 16 ,
0 xBF38, 0 ,
0 xBF39, 0 ,
0 xBF3A, total_expt_addr & 0 x0000FFFF,
0 xBF3B, total_expt_addr >> 16 ,
0 , 0 ,
0 x200e, 0 x0000,
0 xBF3C, total_expt_addr & 0 x0000FFFF,
0 xBF3D, total_expt_addr >> 16 ,
0 xBF3E, 0 ,
0 xBF3F, 0 ,
0 xBF48, 0 ,
0 xBF49, 0 ,
0 xBF4A, calc_q < 4 ? 4 : (calc_q > 124 ? 124 : calc_q),
0 xBF4B, 4 ,
0 xBF4C, 0 ,
0 xBF4D, 0 ,
0 xBF4E, 0 ,
0 xBF4F, 0 ,
0 xBF50, 0 ,
0 xBF51, 0 ,
0 , 0 ,
0 x200e, 0 x0000,
0 xBF40, sgop_expt_addr & 0 x0000FFFF,
0 xBF41, sgop_expt_addr >> 16 ,
0 xBF42, 0 ,
0 xBF43, 0 ,
0 xBF44, 0 ,
0 xBF45, 0 ,
0 xBF46, (go->width >> 4 ) * (go->height >> 4 ),
0 xBF47, 0 ,
0 xBF64, 0 ,
0 xBF65, 0 ,
0 xBF18, framelen[4 ],
0 xBF19, framelen[5 ],
0 xBF1A, framelen[6 ],
0 xBF1B, framelen[7 ],
0 , 0 ,
#if 0
/* Remove once we don't care about matching */
0 x200e, 0 x0000,
0 xBF56, 4 ,
0 xBF57, 0 ,
0 xBF58, 5 ,
0 xBF59, 0 ,
0 xBF5A, 6 ,
0 xBF5B, 0 ,
0 xBF5C, 8 ,
0 xBF5D, 0 ,
0 xBF5E, 1 ,
0 xBF5F, 0 ,
0 xBF60, 1 ,
0 xBF61, 0 ,
0 xBF62, 0 ,
0 xBF63, 0 ,
0 , 0 ,
#else
0 x2008, 0 x0000,
0 xBF56, 4 ,
0 xBF57, 0 ,
0 xBF58, 5 ,
0 xBF59, 0 ,
0 xBF5A, 6 ,
0 xBF5B, 0 ,
0 xBF5C, 8 ,
0 xBF5D, 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
#endif
0 x200e, 0 x0000,
0 xBF10, 0 ,
0 xBF11, 0 ,
0 xBF12, 0 ,
0 xBF13, 0 ,
0 xBF14, 0 ,
0 xBF15, 0 ,
0 xBF16, 0 ,
0 xBF17, 0 ,
0 xBF7E, 0 ,
0 xBF7F, 1 ,
0 xBF52, framelen[0 ],
0 xBF53, framelen[1 ],
0 xBF54, framelen[2 ],
0 xBF55, framelen[3 ],
0 , 0 ,
};
return copy_packages(code, pack , 6 , space);
}
static int config_package(struct go7007 *go, __le16 *code, int space)
{
int fps = go->sensor_framerate / go->fps_scale / 1000 ;
int rows = go->interlace_coding ? go->height / 32 : go->height / 16 ;
int brc_window_size = fps;
int q_min = 2 , q_max = 31 ;
int THACCoeffSet0 = 0 ;
u16 pack [] = {
0 x200e, 0 x0000,
0 xc002, 0 x14b4,
0 xc003, 0 x28b4,
0 xc004, 0 x3c5a,
0 xdc05, 0 x2a77,
0 xc6c3, go->format == V4L2_PIX_FMT_MPEG4 ? 0 :
(go->format == V4L2_PIX_FMT_H263 ? 0 : 1 ),
0 xc680, go->format == V4L2_PIX_FMT_MPEG4 ? 0 xf1 :
(go->format == V4L2_PIX_FMT_H263 ? 0 x61 :
0 xd3),
0 xc780, 0 x0140,
0 xe009, 0 x0001,
0 xc60f, 0 x0008,
0 xd4ff, 0 x0002,
0 xe403, 2340 ,
0 xe406, 75 ,
0 xd411, 0 x0001,
0 xd410, 0 xa1d6,
0 x0001, 0 x2801,
0 x200d, 0 x0000,
0 xe402, 0 x018b,
0 xe401, 0 x8b01,
0 xd472, (go->board_info->sensor_flags &
GO7007_SENSOR_TV) &&
(!go->interlace_coding) ?
0 x01b0 : 0 x0170,
0 xd475, (go->board_info->sensor_flags &
GO7007_SENSOR_TV) &&
(!go->interlace_coding) ?
0 x0008 : 0 x0009,
0 xc404, go->interlace_coding ? 0 x44 :
(go->format == V4L2_PIX_FMT_MPEG4 ? 0 x11 :
(go->format == V4L2_PIX_FMT_MPEG1 ? 0 x02 :
(go->format == V4L2_PIX_FMT_MPEG2 ? 0 x04 :
(go->format == V4L2_PIX_FMT_H263 ? 0 x08 :
0 x20)))),
0 xbf0a, (go->format == V4L2_PIX_FMT_MPEG4 ? 8 :
(go->format == V4L2_PIX_FMT_MPEG1 ? 1 :
(go->format == V4L2_PIX_FMT_MPEG2 ? 2 :
(go->format == V4L2_PIX_FMT_H263 ? 4 : 16 )))) |
((go->repeat_seqhead ? 1 : 0 ) << 6 ) |
((go->dvd_mode ? 1 : 0 ) << 9 ) |
((go->gop_header_enable ? 1 : 0 ) << 10 ),
0 xbf0b, 0 ,
0 xdd5a, go->ipb ? 0 x14 : 0 x0a,
0 xbf0c, 0 ,
0 xbf0d, 0 ,
0 xc683, THACCoeffSet0,
0 xc40a, (go->width << 4 ) | rows,
0 xe01a, go->board_info->hpi_buffer_cap,
0 , 0 ,
0 , 0 ,
0 x2008, 0 ,
0 xe402, 0 x88,
0 xe401, 0 x8f01,
0 xbf6a, 0 ,
0 xbf6b, 0 ,
0 xbf6c, 0 ,
0 xbf6d, 0 ,
0 xbf6e, 0 ,
0 xbf6f, 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 x200e, 0 ,
0 xbf66, brc_window_size,
0 xbf67, 0 ,
0 xbf68, q_min,
0 xbf69, q_max,
0 xbfe0, 0 ,
0 xbfe1, 0 ,
0 xbfe2, 0 ,
0 xbfe3, go->ipb ? 3 : 1 ,
0 xc031, go->board_info->sensor_flags &
GO7007_SENSOR_VBI ? 1 : 0 ,
0 xc01c, 0 x1f,
0 xdd8c, 0 x15,
0 xdd94, 0 x15,
0 xdd88, go->ipb ? 0 x1401 : 0 x0a01,
0 xdd90, go->ipb ? 0 x1401 : 0 x0a01,
0 , 0 ,
0 x200e, 0 ,
0 xbfe4, 0 ,
0 xbfe5, 0 ,
0 xbfe6, 0 ,
0 xbfe7, fps << 8 ,
0 xbfe8, 0 x3a00,
0 xbfe9, 0 ,
0 xbfea, 0 ,
0 xbfeb, 0 ,
0 xbfec, (go->interlace_coding ? 1 << 15 : 0 ) |
(go->modet_enable ? 0 xa : 0 ) |
(go->board_info->sensor_flags &
GO7007_SENSOR_VBI ? 1 : 0 ),
0 xbfed, 0 ,
0 xbfee, 0 ,
0 xbfef, 0 ,
0 xbff0, go->board_info->sensor_flags &
GO7007_SENSOR_TV ? 0 xf060 : 0 xb060,
0 xbff1, 0 ,
0 , 0 ,
};
return copy_packages(code, pack , 5 , space);
}
static int seqhead_to_package(struct go7007 *go, __le16 *code, int space,
int (*sequence_header_func)(struct go7007 *go,
unsigned char *buf, int ext))
{
int vop_time_increment_bitlength = vti_bitlen(go);
int fps = go->sensor_framerate / go->fps_scale *
(go->interlace_coding ? 2 : 1 );
unsigned char buf[40 ] = { };
int len = sequence_header_func(go, buf, 1 );
u16 pack [] = {
0 x2006, 0 ,
0 xbf08, fps,
0 xbf09, 0 ,
0 xbff2, vop_time_increment_bitlength,
0 xbff3, (1 << vop_time_increment_bitlength) - 1 ,
0 xbfe6, 0 ,
0 xbfe7, (fps / 1000 ) << 8 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 x2007, 0 ,
0 xc800, buf[2 ] << 8 | buf[3 ],
0 xc801, buf[4 ] << 8 | buf[5 ],
0 xc802, buf[6 ] << 8 | buf[7 ],
0 xc803, buf[8 ] << 8 | buf[9 ],
0 xc406, 64 ,
0 xc407, len - 64 ,
0 xc61b, 1 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 x200e, 0 ,
0 xc808, buf[10 ] << 8 | buf[11 ],
0 xc809, buf[12 ] << 8 | buf[13 ],
0 xc80a, buf[14 ] << 8 | buf[15 ],
0 xc80b, buf[16 ] << 8 | buf[17 ],
0 xc80c, buf[18 ] << 8 | buf[19 ],
0 xc80d, buf[20 ] << 8 | buf[21 ],
0 xc80e, buf[22 ] << 8 | buf[23 ],
0 xc80f, buf[24 ] << 8 | buf[25 ],
0 xc810, buf[26 ] << 8 | buf[27 ],
0 xc811, buf[28 ] << 8 | buf[29 ],
0 xc812, buf[30 ] << 8 | buf[31 ],
0 xc813, buf[32 ] << 8 | buf[33 ],
0 xc814, buf[34 ] << 8 | buf[35 ],
0 xc815, buf[36 ] << 8 | buf[37 ],
0 , 0 ,
0 , 0 ,
0 , 0 ,
};
return copy_packages(code, pack , 3 , space);
}
static int relative_prime(int big, int little)
{
int remainder;
while (little != 0 ) {
remainder = big % little;
big = little;
little = remainder;
}
return big;
}
static int avsync_to_package(struct go7007 *go, __le16 *code, int space)
{
int arate = go->board_info->audio_rate * 1001 * go->fps_scale;
int ratio = arate / go->sensor_framerate;
int adjratio = ratio * 215 / 100 ;
int rprime = relative_prime(go->sensor_framerate,
arate % go->sensor_framerate);
int f1 = (arate % go->sensor_framerate) / rprime;
int f2 = (go->sensor_framerate - arate % go->sensor_framerate) / rprime;
u16 pack [] = {
0 x200e, 0 ,
0 xbf98, (u16)((-adjratio) & 0 xffff),
0 xbf99, (u16)((-adjratio) >> 16 ),
0 xbf92, 0 ,
0 xbf93, 0 ,
0 xbff4, max(f1, f2),
0 xbff5, min(f1, f2),
0 xbff6, f1 < f2 ? ratio : ratio + 1 ,
0 xbff7, f1 > f2 ? ratio : ratio + 1 ,
0 xbff8, 0 ,
0 xbff9, 0 ,
0 xbffa, adjratio & 0 xffff,
0 xbffb, adjratio >> 16 ,
0 xbf94, 0 ,
0 xbf95, 0 ,
0 , 0 ,
};
return copy_packages(code, pack , 1 , space);
}
static int final_package(struct go7007 *go, __le16 *code, int space)
{
int rows = go->interlace_coding ? go->height / 32 : go->height / 16 ;
u16 pack [] = {
0 x8000,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
2 ,
((go->board_info->sensor_flags & GO7007_SENSOR_TV) &&
(!go->interlace_coding) ?
(1 << 14 ) | (1 << 9 ) : 0 ) |
((go->encoder_subsample ? 1 : 0 ) << 8 ) |
(go->board_info->sensor_flags &
GO7007_SENSOR_CONFIG_MASK),
((go->encoder_v_halve ? 1 : 0 ) << 14 ) |
(go->encoder_v_halve ? rows << 9 : rows << 8 ) |
(go->encoder_h_halve ? 1 << 6 : 0 ) |
(go->encoder_h_halve ? go->width >> 3 : go->width >> 4 ),
(1 << 15 ) | (go->encoder_v_offset << 6 ) |
(1 << 7 ) | (go->encoder_h_offset >> 2 ),
(1 << 6 ),
0 ,
0 ,
((go->fps_scale - 1 ) << 8 ) |
(go->board_info->sensor_flags & GO7007_SENSOR_TV ?
(1 << 7 ) : 0 ) |
0 x41,
go->ipb ? 0 xd4c : 0 x36b,
(rows << 8 ) | (go->width >> 4 ),
go->format == V4L2_PIX_FMT_MPEG4 ? 0 x0404 : 0 ,
(1 << 15 ) | ((go->interlace_coding ? 1 : 0 ) << 13 ) |
((go->closed_gop ? 1 : 0 ) << 12 ) |
((go->format == V4L2_PIX_FMT_MPEG4 ? 1 : 0 ) << 11 ) |
/* (1 << 9) | */
((go->ipb ? 3 : 0 ) << 7 ) |
((go->modet_enable ? 1 : 0 ) << 2 ) |
((go->dvd_mode ? 1 : 0 ) << 1 ) | 1 ,
(go->format == V4L2_PIX_FMT_MPEG1 ? 0 x89a0 :
(go->format == V4L2_PIX_FMT_MPEG2 ? 0 x89a0 :
(go->format == V4L2_PIX_FMT_MJPEG ? 0 x89a0 :
(go->format == V4L2_PIX_FMT_MPEG4 ? 0 x8920 :
(go->format == V4L2_PIX_FMT_H263 ? 0 x8920 : 0 ))))),
go->ipb ? 0 x1f15 : 0 x1f0b,
go->ipb ? 0 x0015 : 0 x000b,
go->ipb ? 0 xa800 : 0 x5800,
0 xffff,
0 x0020 + 0 x034b * 0 ,
0 x0020 + 0 x034b * 1 ,
0 x0020 + 0 x034b * 2 ,
0 x0020 + 0 x034b * 3 ,
0 x0020 + 0 x034b * 4 ,
0 x0020 + 0 x034b * 5 ,
go->ipb ? (go->gop_size / 3 ) : go->gop_size,
(go->height >> 4 ) * (go->width >> 4 ) * 110 / 100 ,
};
return copy_packages(code, pack , 1 , space);
}
static int audio_to_package(struct go7007 *go, __le16 *code, int space)
{
int clock_config = ((go->board_info->audio_flags &
GO7007_AUDIO_I2S_MASTER ? 1 : 0 ) << 11 ) |
((go->board_info->audio_flags &
GO7007_AUDIO_OKI_MODE ? 1 : 0 ) << 8 ) |
(((go->board_info->audio_bclk_div / 4 ) - 1 ) << 4 ) |
(go->board_info->audio_main_div - 1 );
u16 pack [] = {
0 x200d, 0 ,
0 x9002, 0 ,
0 x9002, 0 ,
0 x9031, 0 ,
0 x9032, 0 ,
0 x9033, 0 ,
0 x9034, 0 ,
0 x9035, 0 ,
0 x9036, 0 ,
0 x9037, 0 ,
0 x9040, 0 ,
0 x9000, clock_config,
0 x9001, (go->board_info->audio_flags & 0 xffff) |
(1 << 9 ),
0 x9000, ((go->board_info->audio_flags &
GO7007_AUDIO_I2S_MASTER ?
1 : 0 ) << 10 ) |
clock_config,
0 , 0 ,
0 , 0 ,
0 x2005, 0 ,
0 x9041, 0 ,
0 x9042, 256 ,
0 x9043, 0 ,
0 x9044, 16 ,
0 x9045, 16 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
0 , 0 ,
};
return copy_packages(code, pack , 2 , space);
}
static int modet_to_package(struct go7007 *go, __le16 *code, int space)
{
bool has_modet0 = go->modet[0 ].enable;
bool has_modet1 = go->modet[1 ].enable;
bool has_modet2 = go->modet[2 ].enable;
bool has_modet3 = go->modet[3 ].enable;
int ret, mb, i, addr, cnt = 0 ;
u16 pack [32 ];
u16 thresholds[] = {
0 x200e, 0 ,
0 xbf82, has_modet0 ? go->modet[0 ].pixel_threshold : 32767 ,
0 xbf83, has_modet1 ? go->modet[1 ].pixel_threshold : 32767 ,
0 xbf84, has_modet2 ? go->modet[2 ].pixel_threshold : 32767 ,
0 xbf85, has_modet3 ? go->modet[3 ].pixel_threshold : 32767 ,
0 xbf86, has_modet0 ? go->modet[0 ].motion_threshold : 32767 ,
0 xbf87, has_modet1 ? go->modet[1 ].motion_threshold : 32767 ,
0 xbf88, has_modet2 ? go->modet[2 ].motion_threshold : 32767 ,
0 xbf89, has_modet3 ? go->modet[3 ].motion_threshold : 32767 ,
0 xbf8a, has_modet0 ? go->modet[0 ].mb_threshold : 32767 ,
0 xbf8b, has_modet1 ? go->modet[1 ].mb_threshold : 32767 ,
0 xbf8c, has_modet2 ? go->modet[2 ].mb_threshold : 32767 ,
0 xbf8d, has_modet3 ? go->modet[3 ].mb_threshold : 32767 ,
0 xbf8e, 0 ,
0 xbf8f, 0 ,
0 , 0 ,
};
ret = copy_packages(code, thresholds, 1 , space);
if (ret < 0 )
return -1 ;
cnt += ret;
addr = 0 xbac0;
memset(pack , 0 , 64 );
i = 0 ;
for (mb = 0 ; mb < 1624 ; ++mb) {
pack [i * 2 + 3 ] <<= 2 ;
pack [i * 2 + 3 ] |= go->modet_map[mb];
if (mb % 8 != 7 )
continue ;
pack [i * 2 + 2 ] = addr++;
++i;
if (i == 10 || mb == 1623 ) {
pack [0 ] = 0 x2000 | i;
ret = copy_packages(code + cnt, pack , 1 , space - cnt);
if (ret < 0 )
return -1 ;
cnt += ret;
i = 0 ;
memset(pack , 0 , 64 );
}
pack [i * 2 + 3 ] = 0 ;
}
memset(pack , 0 , 64 );
i = 0 ;
for (addr = 0 xbb90; addr < 0 xbbfa; ++addr) {
pack [i * 2 + 2 ] = addr;
pack [i * 2 + 3 ] = 0 ;
++i;
if (i == 10 || addr == 0 xbbf9) {
pack [0 ] = 0 x2000 | i;
ret = copy_packages(code + cnt, pack , 1 , space - cnt);
if (ret < 0 )
return -1 ;
cnt += ret;
i = 0 ;
memset(pack , 0 , 64 );
}
}
return cnt;
}
static noinline_for_stack int do_special(struct go7007 *go, u16 type,
__le16 *code, int space, int *framelen)
{
switch (type) {
case SPECIAL_FRM_HEAD:
switch (go->format) {
case V4L2_PIX_FMT_MJPEG:
return gen_mjpeghdr_to_package(go, code, space);
case V4L2_PIX_FMT_MPEG1:
case V4L2_PIX_FMT_MPEG2:
return gen_mpeg1hdr_to_package(go, code, space,
framelen);
case V4L2_PIX_FMT_MPEG4:
return gen_mpeg4hdr_to_package(go, code, space,
framelen);
default :
break ;
}
break ;
case SPECIAL_BRC_CTRL:
return brctrl_to_package(go, code, space, framelen);
case SPECIAL_CONFIG:
return config_package(go, code, space);
case SPECIAL_SEQHEAD:
switch (go->format) {
case V4L2_PIX_FMT_MPEG1:
case V4L2_PIX_FMT_MPEG2:
return seqhead_to_package(go, code, space,
mpeg1_sequence_header);
case V4L2_PIX_FMT_MPEG4:
return seqhead_to_package(go, code, space,
mpeg4_sequence_header);
default :
return 0 ;
}
case SPECIAL_AV_SYNC:
return avsync_to_package(go, code, space);
case SPECIAL_FINAL:
return final_package(go, code, space);
case SPECIAL_AUDIO:
return audio_to_package(go, code, space);
case SPECIAL_MODET:
return modet_to_package(go, code, space);
}
dev_err(go->dev,
"firmware file contains unsupported feature %04x\n" , type);
return -1 ;
}
int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen)
{
const struct firmware *fw_entry;
__le16 *code, *src;
int framelen[8 ] = { }; /* holds the lengths of empty frame templates */
int codespace = 64 * 1024 , i = 0 , srclen, chunk_len, chunk_flags;
int mode_flag;
int ret;
switch (go->format) {
case V4L2_PIX_FMT_MJPEG:
mode_flag = FLAG_MODE_MJPEG;
break ;
case V4L2_PIX_FMT_MPEG1:
mode_flag = FLAG_MODE_MPEG1;
break ;
case V4L2_PIX_FMT_MPEG2:
mode_flag = FLAG_MODE_MPEG2;
break ;
case V4L2_PIX_FMT_MPEG4:
mode_flag = FLAG_MODE_MPEG4;
break ;
default :
return -1 ;
}
if (request_firmware(&fw_entry, GO7007_FW_NAME, go->dev)) {
dev_err(go->dev,
"unable to load firmware from file \" %s\"\n" ,
GO7007_FW_NAME);
return -1 ;
}
code = kcalloc(codespace, 2 , GFP_KERNEL);
if (code == NULL)
goto fw_failed;
src = (__le16 *)fw_entry->data;
srclen = fw_entry->size / 2 ;
while (srclen >= 2 ) {
chunk_flags = __le16_to_cpu(src[0 ]);
chunk_len = __le16_to_cpu(src[1 ]);
if (chunk_len + 2 > srclen) {
dev_err(go->dev,
"firmware file \" %s\" appears to be corrupted\n" ,
GO7007_FW_NAME);
goto fw_failed;
}
if (chunk_flags & mode_flag) {
if (chunk_flags & FLAG_SPECIAL) {
ret = do_special(go, __le16_to_cpu(src[2 ]),
&code[i], codespace - i, framelen);
if (ret < 0 ) {
dev_err(go->dev,
"insufficient memory for firmware construction\n" );
goto fw_failed;
}
i += ret;
} else {
if (codespace - i < chunk_len) {
dev_err(go->dev,
"insufficient memory for firmware construction\n" );
goto fw_failed;
}
memcpy(&code[i], &src[2 ], chunk_len * 2 );
i += chunk_len;
}
}
srclen -= chunk_len + 2 ;
src += chunk_len + 2 ;
}
release_firmware(fw_entry);
*fw = (u8 *)code;
*fwlen = i * 2 ;
return 0 ;
fw_failed:
kfree(code);
release_firmware(fw_entry);
return -1 ;
}
MODULE_FIRMWARE(GO7007_FW_NAME);
Messung V0.5 in Prozent C=95 H=94 G=94
¤ Dauer der Verarbeitung: 0.24 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland