1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Zoran ZR36060 basic configuration functions
5 * Copyright (C) 2002 Laurent Pinchart <laurent.pinchart@skynet.be>
8 #include <linux/module.h>
9 #include <linux/init.h>
10 #include <linux/slab.h>
11 #include <linux/delay.h>
13 #include <linux/types.h>
14 #include <linux/wait.h>
16 /* I/O commands, error codes */
19 /* headerfile of this module */
23 #include "videocodec.h"
25 /* it doesn't make sense to have more than 20 or so, just to prevent some unwanted loops */
28 /* amount of chips attached via this driver */
29 static int zr36060_codecs
;
31 static bool low_bitrate
;
32 module_param(low_bitrate
, bool, 0);
33 MODULE_PARM_DESC(low_bitrate
, "Buz compatibility option, halves bitrate");
35 /* =========================================================================
36 * Local hardware I/O functions:
37 * read/write via codec layer (registers are located in the master device)
38 * =========================================================================
41 static u8
zr36060_read(struct zr36060
*ptr
, u16 reg
)
44 struct zoran
*zr
= videocodec_to_zoran(ptr
->codec
);
46 // just in case something is wrong...
47 if (ptr
->codec
->master_data
->readreg
)
48 value
= (ptr
->codec
->master_data
->readreg(ptr
->codec
, reg
)) & 0xff;
50 zrdev_err(zr
, "%s: invalid I/O setup, nothing read!\n", ptr
->name
);
55 static void zr36060_write(struct zr36060
*ptr
, u16 reg
, u8 value
)
57 struct zoran
*zr
= videocodec_to_zoran(ptr
->codec
);
59 zrdev_dbg(zr
, "0x%02x @0x%04x\n", value
, reg
);
61 // just in case something is wrong...
62 if (ptr
->codec
->master_data
->writereg
)
63 ptr
->codec
->master_data
->writereg(ptr
->codec
, reg
, value
);
65 zrdev_err(zr
, "%s: invalid I/O setup, nothing written!\n", ptr
->name
);
68 /* =========================================================================
69 * Local helper function:
71 * =========================================================================
74 /* status is kept in datastructure */
75 static u8
zr36060_read_status(struct zr36060
*ptr
)
77 ptr
->status
= zr36060_read(ptr
, ZR060_CFSR
);
83 /* scale factor is kept in datastructure */
84 static u16
zr36060_read_scalefactor(struct zr36060
*ptr
)
86 ptr
->scalefact
= (zr36060_read(ptr
, ZR060_SF_HI
) << 8) |
87 (zr36060_read(ptr
, ZR060_SF_LO
) & 0xFF);
89 /* leave 0 selected for an eventually GO from master */
91 return ptr
->scalefact
;
94 /* wait if codec is ready to proceed (end of processing) or time is over */
95 static void zr36060_wait_end(struct zr36060
*ptr
)
97 struct zoran
*zr
= videocodec_to_zoran(ptr
->codec
);
100 while (zr36060_read_status(ptr
) & ZR060_CFSR_BUSY
) {
102 if (i
++ > 200000) { // 200ms, there is for sure something wrong!!!
104 "%s: timeout at wait_end (last status: 0x%02x)\n",
105 ptr
->name
, ptr
->status
);
111 /* Basic test of "connectivity", writes/reads to/from memory the SOF marker */
112 static int zr36060_basic_test(struct zr36060
*ptr
)
114 struct zoran
*zr
= videocodec_to_zoran(ptr
->codec
);
116 if ((zr36060_read(ptr
, ZR060_IDR_DEV
) != 0x33) &&
117 (zr36060_read(ptr
, ZR060_IDR_REV
) != 0x01)) {
118 zrdev_err(zr
, "%s: attach failed, can't connect to jpeg processor!\n", ptr
->name
);
122 zr36060_wait_end(ptr
);
123 if (ptr
->status
& ZR060_CFSR_BUSY
) {
124 zrdev_err(zr
, "%s: attach failed, jpeg processor failed (end flag)!\n", ptr
->name
);
128 return 0; /* looks good! */
131 /* simple loop for pushing the init datasets */
132 static int zr36060_pushit(struct zr36060
*ptr
, u16 startreg
, u16 len
, const char *data
)
134 struct zoran
*zr
= videocodec_to_zoran(ptr
->codec
);
137 zrdev_dbg(zr
, "%s: write data block to 0x%04x (len=%d)\n", ptr
->name
,
140 zr36060_write(ptr
, startreg
++, data
[i
++]);
145 /* =========================================================================
147 * jpeg baseline setup data (you find it on lots places in internet, or just
148 * extract it from any regular .jpg image...)
150 * Could be variable, but until it's not needed it they are just fixed to save
151 * memory. Otherwise expand zr36060 structure with arrays, push the values to
152 * it and initialize from there, as e.g. the linux zr36057/60 driver does it.
153 * =========================================================================
155 static const char zr36060_dqt
[0x86] = {
156 0xff, 0xdb, //Marker: DQT
157 0x00, 0x84, //Length: 2*65+2
158 0x00, //Pq,Tq first table
159 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e,
160 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28,
161 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
162 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33,
163 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44,
164 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57,
165 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71,
166 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63,
167 0x01, //Pq,Tq second table
168 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a,
169 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63,
170 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
171 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
172 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
173 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
174 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
175 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63
178 static const char zr36060_dht
[0x1a4] = {
179 0xff, 0xc4, //Marker: DHT
180 0x01, 0xa2, //Length: 2*AC, 2*DC
181 0x00, //DC first table
182 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
183 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
184 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
185 0x01, //DC second table
186 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
187 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
188 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
189 0x10, //AC first table
190 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
191 0x05, 0x05, 0x04, 0x04, 0x00, 0x00,
192 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11,
193 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61,
194 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1,
195 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24,
196 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17,
197 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34,
198 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44,
199 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56,
200 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66,
201 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
202 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
203 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
204 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
205 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9,
206 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,
207 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9,
208 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
209 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
211 0x11, //AC second table
212 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
213 0x07, 0x05, 0x04, 0x04, 0x00, 0x01,
214 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
215 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
216 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
217 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62,
218 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25,
219 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A,
220 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44,
221 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56,
222 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66,
223 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
224 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
225 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
226 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
227 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8,
228 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
229 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8,
230 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
231 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
235 /* jpeg baseline setup, this is just fixed in this driver (YUV pictures) */
236 #define NO_OF_COMPONENTS 0x3 //Y,U,V
237 #define BASELINE_PRECISION 0x8 //MCU size (?)
238 static const char zr36060_tq
[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's QT
239 static const char zr36060_td
[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's DC
240 static const char zr36060_ta
[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's AC
242 /* horizontal 422 decimation setup (maybe we support 411 or so later, too) */
243 static const char zr36060_decimation_h
[8] = { 2, 1, 1, 0, 0, 0, 0, 0 };
244 static const char zr36060_decimation_v
[8] = { 1, 1, 1, 0, 0, 0, 0, 0 };
247 * SOF (start of frame) segment depends on width, height and sampling ratio
248 * of each color component
250 static int zr36060_set_sof(struct zr36060
*ptr
)
252 struct zoran
*zr
= videocodec_to_zoran(ptr
->codec
);
253 char sof_data
[34]; // max. size of register set
256 zrdev_dbg(zr
, "%s: write SOF (%dx%d, %d components)\n", ptr
->name
,
257 ptr
->width
, ptr
->height
, NO_OF_COMPONENTS
);
261 sof_data
[3] = (3 * NO_OF_COMPONENTS
) + 8;
262 sof_data
[4] = BASELINE_PRECISION
; // only '8' possible with zr36060
263 sof_data
[5] = (ptr
->height
) >> 8;
264 sof_data
[6] = (ptr
->height
) & 0xff;
265 sof_data
[7] = (ptr
->width
) >> 8;
266 sof_data
[8] = (ptr
->width
) & 0xff;
267 sof_data
[9] = NO_OF_COMPONENTS
;
268 for (i
= 0; i
< NO_OF_COMPONENTS
; i
++) {
269 sof_data
[10 + (i
* 3)] = i
; // index identifier
270 sof_data
[11 + (i
* 3)] = (ptr
->h_samp_ratio
[i
] << 4) |
271 (ptr
->v_samp_ratio
[i
]); // sampling ratios
272 sof_data
[12 + (i
* 3)] = zr36060_tq
[i
]; // Q table selection
274 return zr36060_pushit(ptr
, ZR060_SOF_IDX
,
275 (3 * NO_OF_COMPONENTS
) + 10, sof_data
);
278 /* SOS (start of scan) segment depends on the used scan components of each color component */
279 static int zr36060_set_sos(struct zr36060
*ptr
)
281 struct zoran
*zr
= videocodec_to_zoran(ptr
->codec
);
282 char sos_data
[16]; // max. size of register set
285 zrdev_dbg(zr
, "%s: write SOS\n", ptr
->name
);
289 sos_data
[3] = 2 + 1 + (2 * NO_OF_COMPONENTS
) + 3;
290 sos_data
[4] = NO_OF_COMPONENTS
;
291 for (i
= 0; i
< NO_OF_COMPONENTS
; i
++) {
292 sos_data
[5 + (i
* 2)] = i
; // index
293 sos_data
[6 + (i
* 2)] = (zr36060_td
[i
] << 4) |
294 zr36060_ta
[i
]; // AC/DC tbl.sel.
296 sos_data
[2 + 1 + (2 * NO_OF_COMPONENTS
) + 2] = 00; // scan start
297 sos_data
[2 + 1 + (2 * NO_OF_COMPONENTS
) + 3] = 0x3f;
298 sos_data
[2 + 1 + (2 * NO_OF_COMPONENTS
) + 4] = 00;
299 return zr36060_pushit(ptr
, ZR060_SOS_IDX
,
300 4 + 1 + (2 * NO_OF_COMPONENTS
) + 3,
304 /* DRI (define restart interval) */
305 static int zr36060_set_dri(struct zr36060
*ptr
)
307 struct zoran
*zr
= videocodec_to_zoran(ptr
->codec
);
308 char dri_data
[6]; // max. size of register set
310 zrdev_dbg(zr
, "%s: write DRI\n", ptr
->name
);
315 dri_data
[4] = (ptr
->dri
) >> 8;
316 dri_data
[5] = (ptr
->dri
) & 0xff;
317 return zr36060_pushit(ptr
, ZR060_DRI_IDX
, 6, dri_data
);
320 /* Setup compression/decompression of Zoran's JPEG processor ( see also zoran 36060 manual )
321 * ... sorry for the spaghetti code ...
323 static void zr36060_init(struct zr36060
*ptr
)
327 struct zoran
*zr
= videocodec_to_zoran(ptr
->codec
);
329 if (ptr
->mode
== CODEC_DO_COMPRESSION
) {
330 zrdev_dbg(zr
, "%s: COMPRESSION SETUP\n", ptr
->name
);
332 zr36060_write(ptr
, ZR060_LOAD
, ZR060_LOAD_SYNC_RST
);
334 /* 060 communicates with 067 in master mode */
335 zr36060_write(ptr
, ZR060_CIR
, ZR060_CIR_CODE_MSTR
);
337 /* Compression with or without variable scale factor */
338 /*FIXME: What about ptr->bitrate_ctrl? */
339 zr36060_write(ptr
, ZR060_CMR
, ZR060_CMR_COMP
| ZR060_CMR_PASS2
| ZR060_CMR_BRB
);
342 zr36060_write(ptr
, ZR060_MBZ
, 0x00);
343 zr36060_write(ptr
, ZR060_TCR_HI
, 0x00);
344 zr36060_write(ptr
, ZR060_TCR_LO
, 0x00);
346 /* Disable all IRQs - no DataErr means autoreset */
347 zr36060_write(ptr
, ZR060_IMR
, 0);
349 /* volume control settings */
350 zr36060_write(ptr
, ZR060_SF_HI
, ptr
->scalefact
>> 8);
351 zr36060_write(ptr
, ZR060_SF_LO
, ptr
->scalefact
& 0xff);
353 zr36060_write(ptr
, ZR060_AF_HI
, 0xff);
354 zr36060_write(ptr
, ZR060_AF_M
, 0xff);
355 zr36060_write(ptr
, ZR060_AF_LO
, 0xff);
357 /* setup the variable jpeg tables */
358 sum
+= zr36060_set_sof(ptr
);
359 sum
+= zr36060_set_sos(ptr
);
360 sum
+= zr36060_set_dri(ptr
);
362 /* setup the fixed jpeg tables - maybe variable, though - (see table init section above) */
363 sum
+= zr36060_pushit(ptr
, ZR060_DQT_IDX
, sizeof(zr36060_dqt
), zr36060_dqt
);
364 sum
+= zr36060_pushit(ptr
, ZR060_DHT_IDX
, sizeof(zr36060_dht
), zr36060_dht
);
365 zr36060_write(ptr
, ZR060_APP_IDX
, 0xff);
366 zr36060_write(ptr
, ZR060_APP_IDX
+ 1, 0xe0 + ptr
->app
.appn
);
367 zr36060_write(ptr
, ZR060_APP_IDX
+ 2, 0x00);
368 zr36060_write(ptr
, ZR060_APP_IDX
+ 3, ptr
->app
.len
+ 2);
369 sum
+= zr36060_pushit(ptr
, ZR060_APP_IDX
+ 4, 60, ptr
->app
.data
) + 4;
370 zr36060_write(ptr
, ZR060_COM_IDX
, 0xff);
371 zr36060_write(ptr
, ZR060_COM_IDX
+ 1, 0xfe);
372 zr36060_write(ptr
, ZR060_COM_IDX
+ 2, 0x00);
373 zr36060_write(ptr
, ZR060_COM_IDX
+ 3, ptr
->com
.len
+ 2);
374 sum
+= zr36060_pushit(ptr
, ZR060_COM_IDX
+ 4, 60, ptr
->com
.data
) + 4;
376 /* setup misc. data for compression (target code sizes) */
378 /* size of compressed code to reach without header data */
379 sum
= ptr
->real_code_vol
- sum
;
380 bitcnt
= sum
<< 3; /* need the size in bits */
384 "%s: code: csize=%d, tot=%d, bit=%ld, highbits=%ld\n",
385 ptr
->name
, sum
, ptr
->real_code_vol
, bitcnt
, tmp
);
386 zr36060_write(ptr
, ZR060_TCV_NET_HI
, tmp
>> 8);
387 zr36060_write(ptr
, ZR060_TCV_NET_MH
, tmp
& 0xff);
388 tmp
= bitcnt
& 0xffff;
389 zr36060_write(ptr
, ZR060_TCV_NET_ML
, tmp
>> 8);
390 zr36060_write(ptr
, ZR060_TCV_NET_LO
, tmp
& 0xff);
392 bitcnt
-= bitcnt
>> 7; // bits without stuffing
393 bitcnt
-= ((bitcnt
* 5) >> 6); // bits without eob
396 zrdev_dbg(zr
, "%s: code: nettobit=%ld, highnettobits=%ld\n",
397 ptr
->name
, bitcnt
, tmp
);
398 zr36060_write(ptr
, ZR060_TCV_DATA_HI
, tmp
>> 8);
399 zr36060_write(ptr
, ZR060_TCV_DATA_MH
, tmp
& 0xff);
400 tmp
= bitcnt
& 0xffff;
401 zr36060_write(ptr
, ZR060_TCV_DATA_ML
, tmp
>> 8);
402 zr36060_write(ptr
, ZR060_TCV_DATA_LO
, tmp
& 0xff);
404 /* JPEG markers to be included in the compressed stream */
405 zr36060_write(ptr
, ZR060_MER
,
406 ZR060_MER_DQT
| ZR060_MER_DHT
|
407 ((ptr
->com
.len
> 0) ? ZR060_MER_COM
: 0) |
408 ((ptr
->app
.len
> 0) ? ZR060_MER_APP
: 0));
410 /* Setup the Video Frontend */
411 /* Limit pixel range to 16..235 as per CCIR-601 */
412 zr36060_write(ptr
, ZR060_VCR
, ZR060_VCR_RANGE
);
415 zrdev_dbg(zr
, "%s: EXPANSION SETUP\n", ptr
->name
);
417 zr36060_write(ptr
, ZR060_LOAD
, ZR060_LOAD_SYNC_RST
);
419 /* 060 communicates with 067 in master mode */
420 zr36060_write(ptr
, ZR060_CIR
, ZR060_CIR_CODE_MSTR
);
423 zr36060_write(ptr
, ZR060_CMR
, 0);
426 zr36060_write(ptr
, ZR060_MBZ
, 0x00);
427 zr36060_write(ptr
, ZR060_TCR_HI
, 0x00);
428 zr36060_write(ptr
, ZR060_TCR_LO
, 0x00);
430 /* Disable all IRQs - no DataErr means autoreset */
431 zr36060_write(ptr
, ZR060_IMR
, 0);
433 /* setup misc. data for expansion */
434 zr36060_write(ptr
, ZR060_MER
, 0);
436 /* setup the fixed jpeg tables - maybe variable, though - (see table init section above) */
437 zr36060_pushit(ptr
, ZR060_DHT_IDX
, sizeof(zr36060_dht
), zr36060_dht
);
439 /* Setup the Video Frontend */
440 //zr36060_write(ptr, ZR060_VCR, ZR060_VCR_FI_EXT);
441 //this doesn't seem right and doesn't work...
442 zr36060_write(ptr
, ZR060_VCR
, ZR060_VCR_RANGE
);
445 /* Load the tables */
446 zr36060_write(ptr
, ZR060_LOAD
, ZR060_LOAD_SYNC_RST
| ZR060_LOAD_LOAD
);
447 zr36060_wait_end(ptr
);
448 zrdev_dbg(zr
, "%s: Status after table preload: 0x%02x\n",
449 ptr
->name
, ptr
->status
);
451 if (ptr
->status
& ZR060_CFSR_BUSY
) {
452 zrdev_err(zr
, "%s: init aborted!\n", ptr
->name
);
453 return; // something is wrong, its timed out!!!!
457 /* =========================================================================
458 * CODEC API FUNCTIONS
459 * this functions are accessed by the master via the API structure
460 * =========================================================================
463 /* set compressiion/expansion mode and launches codec -
464 * this should be the last call from the master before starting processing
466 static int zr36060_set_mode(struct videocodec
*codec
, int mode
)
468 struct zr36060
*ptr
= (struct zr36060
*)codec
->data
;
469 struct zoran
*zr
= videocodec_to_zoran(codec
);
471 zrdev_dbg(zr
, "%s: set_mode %d call\n", ptr
->name
, mode
);
473 if (mode
!= CODEC_DO_EXPANSION
&& mode
!= CODEC_DO_COMPRESSION
)
482 /* set picture size (norm is ignored as the codec doesn't know about it) */
483 static int zr36060_set_video(struct videocodec
*codec
, const struct tvnorm
*norm
,
484 struct vfe_settings
*cap
, struct vfe_polarity
*pol
)
486 struct zr36060
*ptr
= (struct zr36060
*)codec
->data
;
487 struct zoran
*zr
= videocodec_to_zoran(codec
);
491 zrdev_dbg(zr
, "%s: set_video %d/%d-%dx%d (%%%d) call\n", ptr
->name
,
492 cap
->x
, cap
->y
, cap
->width
, cap
->height
, cap
->decimation
);
494 /* if () return -EINVAL;
495 * trust the master driver that it knows what it does - so
496 * we allow invalid startx/y and norm for now ...
498 ptr
->width
= cap
->width
/ (cap
->decimation
& 0xff);
499 ptr
->height
= cap
->height
/ (cap
->decimation
>> 8);
501 zr36060_write(ptr
, ZR060_LOAD
, ZR060_LOAD_SYNC_RST
);
503 /* Note that VSPol/HSPol bits in zr36060 have the opposite
504 * meaning of their zr360x7 counterparts with the same names
505 * N.b. for VSPol this is only true if FIVEdge = 0 (default,
506 * left unchanged here - in accordance with datasheet).
508 reg
= (!pol
->vsync_pol
? ZR060_VPR_VS_POL
: 0)
509 | (!pol
->hsync_pol
? ZR060_VPR_HS_POL
: 0)
510 | (pol
->field_pol
? ZR060_VPR_FI_POL
: 0)
511 | (pol
->blank_pol
? ZR060_VPR_BL_POL
: 0)
512 | (pol
->subimg_pol
? ZR060_VPR_S_IMG_POL
: 0)
513 | (pol
->poe_pol
? ZR060_VPR_POE_POL
: 0)
514 | (pol
->pvalid_pol
? ZR060_VPR_P_VAL_POL
: 0)
515 | (pol
->vclk_pol
? ZR060_VPR_VCLK_POL
: 0);
516 zr36060_write(ptr
, ZR060_VPR
, reg
);
519 switch (cap
->decimation
& 0xff) {
525 reg
|= ZR060_SR_H_SCALE2
;
529 reg
|= ZR060_SR_H_SCALE4
;
533 switch (cap
->decimation
>> 8) {
539 reg
|= ZR060_SR_V_SCALE
;
542 zr36060_write(ptr
, ZR060_SR
, reg
);
544 zr36060_write(ptr
, ZR060_BCR_Y
, 0x00);
545 zr36060_write(ptr
, ZR060_BCR_U
, 0x80);
546 zr36060_write(ptr
, ZR060_BCR_V
, 0x80);
550 reg
= norm
->ht
- 1; /* Vtotal */
551 zr36060_write(ptr
, ZR060_SGR_VTOTAL_HI
, (reg
>> 8) & 0xff);
552 zr36060_write(ptr
, ZR060_SGR_VTOTAL_LO
, (reg
>> 0) & 0xff);
554 reg
= norm
->wt
- 1; /* Htotal */
555 zr36060_write(ptr
, ZR060_SGR_HTOTAL_HI
, (reg
>> 8) & 0xff);
556 zr36060_write(ptr
, ZR060_SGR_HTOTAL_LO
, (reg
>> 0) & 0xff);
558 reg
= 6 - 1; /* VsyncSize */
559 zr36060_write(ptr
, ZR060_SGR_VSYNC
, reg
);
562 zr36060_write(ptr
, ZR060_SGR_HSYNC
, reg
);
564 reg
= norm
->v_start
- 1; /* BVstart */
565 zr36060_write(ptr
, ZR060_SGR_BVSTART
, reg
);
567 reg
+= norm
->ha
/ 2; /* BVend */
568 zr36060_write(ptr
, ZR060_SGR_BVEND_HI
, (reg
>> 8) & 0xff);
569 zr36060_write(ptr
, ZR060_SGR_BVEND_LO
, (reg
>> 0) & 0xff);
571 reg
= norm
->h_start
- 1; /* BHstart */
572 zr36060_write(ptr
, ZR060_SGR_BHSTART
, reg
);
574 reg
+= norm
->wa
; /* BHend */
575 zr36060_write(ptr
, ZR060_SGR_BHEND_HI
, (reg
>> 8) & 0xff);
576 zr36060_write(ptr
, ZR060_SGR_BHEND_LO
, (reg
>> 0) & 0xff);
579 reg
= cap
->y
+ norm
->v_start
; /* Vstart */
580 zr36060_write(ptr
, ZR060_AAR_VSTART_HI
, (reg
>> 8) & 0xff);
581 zr36060_write(ptr
, ZR060_AAR_VSTART_LO
, (reg
>> 0) & 0xff);
583 reg
+= cap
->height
; /* Vend */
584 zr36060_write(ptr
, ZR060_AAR_VEND_HI
, (reg
>> 8) & 0xff);
585 zr36060_write(ptr
, ZR060_AAR_VEND_LO
, (reg
>> 0) & 0xff);
587 reg
= cap
->x
+ norm
->h_start
; /* Hstart */
588 zr36060_write(ptr
, ZR060_AAR_HSTART_HI
, (reg
>> 8) & 0xff);
589 zr36060_write(ptr
, ZR060_AAR_HSTART_LO
, (reg
>> 0) & 0xff);
591 reg
+= cap
->width
; /* Hend */
592 zr36060_write(ptr
, ZR060_AAR_HEND_HI
, (reg
>> 8) & 0xff);
593 zr36060_write(ptr
, ZR060_AAR_HEND_LO
, (reg
>> 0) & 0xff);
596 reg
= norm
->v_start
- 4; /* SVstart */
597 zr36060_write(ptr
, ZR060_SWR_VSTART_HI
, (reg
>> 8) & 0xff);
598 zr36060_write(ptr
, ZR060_SWR_VSTART_LO
, (reg
>> 0) & 0xff);
600 reg
+= norm
->ha
/ 2 + 8; /* SVend */
601 zr36060_write(ptr
, ZR060_SWR_VEND_HI
, (reg
>> 8) & 0xff);
602 zr36060_write(ptr
, ZR060_SWR_VEND_LO
, (reg
>> 0) & 0xff);
604 reg
= norm
->h_start
/*+ 64 */ - 4; /* SHstart */
605 zr36060_write(ptr
, ZR060_SWR_HSTART_HI
, (reg
>> 8) & 0xff);
606 zr36060_write(ptr
, ZR060_SWR_HSTART_LO
, (reg
>> 0) & 0xff);
608 reg
+= norm
->wa
+ 8; /* SHend */
609 zr36060_write(ptr
, ZR060_SWR_HEND_HI
, (reg
>> 8) & 0xff);
610 zr36060_write(ptr
, ZR060_SWR_HEND_LO
, (reg
>> 0) & 0xff);
612 size
= ptr
->width
* ptr
->height
;
613 /* Target compressed field size in bits: */
614 size
= size
* 16; /* uncompressed size in bits */
615 /* (Ronald) by default, quality = 100 is a compression
616 * ratio 1:2. Setting low_bitrate (insmod option) sets
617 * it to 1:4 (instead of 1:2, zr36060 max) as limit because the
618 * buz can't handle more at decimation=1... Use low_bitrate if
619 * you have a Buz, unless you know what you're doing
621 size
= size
* cap
->quality
/ (low_bitrate
? 400 : 200);
622 /* Lower limit (arbitrary, 1 KB) */
625 /* Upper limit: 7/8 of the code buffers */
626 if (size
> ptr
->total_code_vol
* 7)
627 size
= ptr
->total_code_vol
* 7;
629 ptr
->real_code_vol
= size
>> 3; /* in bytes */
631 /* the MBCVR is the *maximum* block volume, according to the
632 * JPEG ISO specs, this shouldn't be used, since that allows
633 * for the best encoding quality. So set it to it's max value
635 reg
= ptr
->max_block_vol
;
636 zr36060_write(ptr
, ZR060_MBCVR
, reg
);
641 /* additional control functions */
642 static int zr36060_control(struct videocodec
*codec
, int type
, int size
, void *data
)
644 struct zr36060
*ptr
= (struct zr36060
*)codec
->data
;
645 struct zoran
*zr
= videocodec_to_zoran(codec
);
646 int *ival
= (int *)data
;
648 zrdev_dbg(zr
, "%s: control %d call with %d byte\n", ptr
->name
, type
,
652 case CODEC_G_STATUS
: /* get last status */
653 if (size
!= sizeof(int))
655 zr36060_read_status(ptr
);
659 case CODEC_G_CODEC_MODE
:
660 if (size
!= sizeof(int))
662 *ival
= CODEC_MODE_BJPG
;
665 case CODEC_S_CODEC_MODE
:
666 if (size
!= sizeof(int))
668 if (*ival
!= CODEC_MODE_BJPG
)
670 /* not needed, do nothing */
675 /* not needed, do nothing */
679 /* not available, give an error */
682 case CODEC_G_JPEG_TDS_BYTE
: /* get target volume in byte */
683 if (size
!= sizeof(int))
685 *ival
= ptr
->total_code_vol
;
688 case CODEC_S_JPEG_TDS_BYTE
: /* get target volume in byte */
689 if (size
!= sizeof(int))
691 ptr
->total_code_vol
= *ival
;
692 ptr
->real_code_vol
= (ptr
->total_code_vol
* 6) >> 3;
695 case CODEC_G_JPEG_SCALE
: /* get scaling factor */
696 if (size
!= sizeof(int))
698 *ival
= zr36060_read_scalefactor(ptr
);
701 case CODEC_S_JPEG_SCALE
: /* set scaling factor */
702 if (size
!= sizeof(int))
704 ptr
->scalefact
= *ival
;
707 case CODEC_G_JPEG_APP_DATA
: { /* get appn marker data */
708 struct jpeg_app_marker
*app
= data
;
710 if (size
!= sizeof(struct jpeg_app_marker
))
717 case CODEC_S_JPEG_APP_DATA
: { /* set appn marker data */
718 struct jpeg_app_marker
*app
= data
;
720 if (size
!= sizeof(struct jpeg_app_marker
))
727 case CODEC_G_JPEG_COM_DATA
: { /* get comment marker data */
728 struct jpeg_com_marker
*com
= data
;
730 if (size
!= sizeof(struct jpeg_com_marker
))
737 case CODEC_S_JPEG_COM_DATA
: { /* set comment marker data */
738 struct jpeg_com_marker
*com
= data
;
740 if (size
!= sizeof(struct jpeg_com_marker
))
754 /* =========================================================================
755 * Exit and unregister function:
756 * Deinitializes Zoran's JPEG processor
757 * =========================================================================
759 static int zr36060_unset(struct videocodec
*codec
)
761 struct zr36060
*ptr
= codec
->data
;
762 struct zoran
*zr
= videocodec_to_zoran(codec
);
765 /* do wee need some codec deinit here, too ???? */
767 zrdev_dbg(zr
, "%s: finished codec #%d\n", ptr
->name
, ptr
->num
);
778 /* =========================================================================
779 * Setup and registry function:
780 * Initializes Zoran's JPEG processor
781 * Also sets pixel size, average code size, mode (compr./decompr.)
782 * (the given size is determined by the processor with the video interface)
783 * =========================================================================
785 static int zr36060_setup(struct videocodec
*codec
)
788 struct zoran
*zr
= videocodec_to_zoran(codec
);
791 zrdev_dbg(zr
, "zr36060: initializing MJPEG subsystem #%d.\n",
794 if (zr36060_codecs
== MAX_CODECS
) {
795 zrdev_err(zr
, "zr36060: Can't attach more codecs!\n");
799 ptr
= kzalloc(sizeof(*ptr
), GFP_KERNEL
);
804 snprintf(ptr
->name
, sizeof(ptr
->name
), "zr36060[%d]", zr36060_codecs
);
805 ptr
->num
= zr36060_codecs
++;
809 res
= zr36060_basic_test(ptr
);
811 zr36060_unset(codec
);
815 memcpy(ptr
->h_samp_ratio
, zr36060_decimation_h
, 8);
816 memcpy(ptr
->v_samp_ratio
, zr36060_decimation_v
, 8);
818 ptr
->bitrate_ctrl
= 0; /* 0 or 1 - fixed file size flag (what is the difference?) */
819 ptr
->mode
= CODEC_DO_COMPRESSION
;
822 ptr
->total_code_vol
= 16000; /* CHECKME */
823 ptr
->real_code_vol
= (ptr
->total_code_vol
* 6) >> 3;
824 ptr
->max_block_vol
= 240; /* CHECKME, was 120 is 240 */
825 ptr
->scalefact
= 0x100;
826 ptr
->dri
= 1; /* CHECKME, was 8 is 1 */
828 /* by default, no COM or APP markers - app should set those */
835 zrdev_info(zr
, "%s: codec attached and running\n", ptr
->name
);
840 static const struct videocodec zr36060_codec
= {
842 .magic
= 0L, // magic not used
844 CODEC_FLAG_JPEG
| CODEC_FLAG_HARDWARE
| CODEC_FLAG_ENCODER
|
845 CODEC_FLAG_DECODER
| CODEC_FLAG_VFE
,
846 .type
= CODEC_TYPE_ZR36060
,
847 .setup
= zr36060_setup
, // functionality
848 .unset
= zr36060_unset
,
849 .set_mode
= zr36060_set_mode
,
850 .set_video
= zr36060_set_video
,
851 .control
= zr36060_control
,
852 // others are not used
855 int zr36060_init_module(void)
858 return videocodec_register(&zr36060_codec
);
861 void zr36060_cleanup_module(void)
863 if (zr36060_codecs
) {
864 pr_debug("zr36060: something's wrong - %d codecs left somehow.\n",
868 /* however, we can't just stay alive */
869 videocodec_unregister(&zr36060_codec
);