]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Zoran ZR36050 basic configuration functions | |
3 | * | |
4 | * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at> | |
5 | * | |
6 | * $Id: zr36050.c,v 1.1.2.11 2003/08/03 14:54:53 rbultje Exp $ | |
7 | * | |
8 | * ------------------------------------------------------------------------ | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License as published by | |
12 | * the Free Software Foundation; either version 2 of the License, or | |
13 | * (at your option) any later version. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | * GNU General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU General Public License | |
21 | * along with this program; if not, write to the Free Software | |
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
23 | * | |
24 | * ------------------------------------------------------------------------ | |
25 | */ | |
26 | ||
27 | #define ZR050_VERSION "v0.7.1" | |
28 | ||
1da177e4 LT |
29 | #include <linux/module.h> |
30 | #include <linux/init.h> | |
31 | #include <linux/slab.h> | |
32 | #include <linux/delay.h> | |
33 | ||
34 | #include <linux/types.h> | |
35 | #include <linux/wait.h> | |
36 | ||
1da177e4 | 37 | /* I/O commands, error codes */ |
b9758dfe | 38 | #include <asm/io.h> |
1da177e4 LT |
39 | |
40 | /* headerfile of this module */ | |
b9758dfe | 41 | #include "zr36050.h" |
1da177e4 LT |
42 | |
43 | /* codec io API */ | |
b9758dfe | 44 | #include "videocodec.h" |
1da177e4 LT |
45 | |
46 | /* it doesn't make sense to have more than 20 or so, | |
47 | just to prevent some unwanted loops */ | |
48 | #define MAX_CODECS 20 | |
49 | ||
50 | /* amount of chips attached via this driver */ | |
ff699e6b | 51 | static int zr36050_codecs; |
1da177e4 LT |
52 | |
53 | /* debugging is available via module parameter */ | |
ff699e6b | 54 | static int debug; |
1da177e4 LT |
55 | module_param(debug, int, 0); |
56 | MODULE_PARM_DESC(debug, "Debug level (0-4)"); | |
57 | ||
58 | #define dprintk(num, format, args...) \ | |
59 | do { \ | |
60 | if (debug >= num) \ | |
61 | printk(format, ##args); \ | |
62 | } while (0) | |
63 | ||
64 | /* ========================================================================= | |
65 | Local hardware I/O functions: | |
66 | ||
67 | read/write via codec layer (registers are located in the master device) | |
68 | ========================================================================= */ | |
69 | ||
70 | /* read and write functions */ | |
71 | static u8 | |
72 | zr36050_read (struct zr36050 *ptr, | |
73 | u16 reg) | |
74 | { | |
75 | u8 value = 0; | |
76 | ||
77 | // just in case something is wrong... | |
78 | if (ptr->codec->master_data->readreg) | |
79 | value = (ptr->codec->master_data->readreg(ptr->codec, | |
80 | reg)) & 0xFF; | |
81 | else | |
82 | dprintk(1, | |
83 | KERN_ERR "%s: invalid I/O setup, nothing read!\n", | |
84 | ptr->name); | |
85 | ||
86 | dprintk(4, "%s: reading from 0x%04x: %02x\n", ptr->name, reg, | |
87 | value); | |
88 | ||
89 | return value; | |
90 | } | |
91 | ||
92 | static void | |
93 | zr36050_write (struct zr36050 *ptr, | |
94 | u16 reg, | |
95 | u8 value) | |
96 | { | |
97 | dprintk(4, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value, | |
98 | reg); | |
99 | ||
100 | // just in case something is wrong... | |
101 | if (ptr->codec->master_data->writereg) | |
102 | ptr->codec->master_data->writereg(ptr->codec, reg, value); | |
103 | else | |
104 | dprintk(1, | |
105 | KERN_ERR | |
106 | "%s: invalid I/O setup, nothing written!\n", | |
107 | ptr->name); | |
108 | } | |
109 | ||
110 | /* ========================================================================= | |
111 | Local helper function: | |
112 | ||
113 | status read | |
114 | ========================================================================= */ | |
115 | ||
116 | /* status is kept in datastructure */ | |
117 | static u8 | |
118 | zr36050_read_status1 (struct zr36050 *ptr) | |
119 | { | |
120 | ptr->status1 = zr36050_read(ptr, ZR050_STATUS_1); | |
121 | ||
122 | zr36050_read(ptr, 0); | |
123 | return ptr->status1; | |
124 | } | |
125 | ||
126 | /* ========================================================================= | |
127 | Local helper function: | |
128 | ||
129 | scale factor read | |
130 | ========================================================================= */ | |
131 | ||
132 | /* scale factor is kept in datastructure */ | |
133 | static u16 | |
134 | zr36050_read_scalefactor (struct zr36050 *ptr) | |
135 | { | |
136 | ptr->scalefact = (zr36050_read(ptr, ZR050_SF_HI) << 8) | | |
137 | (zr36050_read(ptr, ZR050_SF_LO) & 0xFF); | |
138 | ||
139 | /* leave 0 selected for an eventually GO from master */ | |
140 | zr36050_read(ptr, 0); | |
141 | return ptr->scalefact; | |
142 | } | |
143 | ||
144 | /* ========================================================================= | |
145 | Local helper function: | |
146 | ||
147 | wait if codec is ready to proceed (end of processing) or time is over | |
148 | ========================================================================= */ | |
149 | ||
150 | static void | |
151 | zr36050_wait_end (struct zr36050 *ptr) | |
152 | { | |
153 | int i = 0; | |
154 | ||
155 | while (!(zr36050_read_status1(ptr) & 0x4)) { | |
156 | udelay(1); | |
8a59822f | 157 | if (i++ > 200000) { // 200ms, there is for sure something wrong!!! |
1da177e4 | 158 | dprintk(1, |
c84e6036 | 159 | "%s: timeout at wait_end (last status: 0x%02x)\n", |
1da177e4 LT |
160 | ptr->name, ptr->status1); |
161 | break; | |
162 | } | |
163 | } | |
164 | } | |
165 | ||
166 | /* ========================================================================= | |
167 | Local helper function: | |
168 | ||
d56410e0 | 169 | basic test of "connectivity", writes/reads to/from memory the SOF marker |
1da177e4 LT |
170 | ========================================================================= */ |
171 | ||
172 | static int | |
173 | zr36050_basic_test (struct zr36050 *ptr) | |
174 | { | |
175 | zr36050_write(ptr, ZR050_SOF_IDX, 0x00); | |
176 | zr36050_write(ptr, ZR050_SOF_IDX + 1, 0x00); | |
177 | if ((zr36050_read(ptr, ZR050_SOF_IDX) | | |
178 | zr36050_read(ptr, ZR050_SOF_IDX + 1)) != 0x0000) { | |
179 | dprintk(1, | |
180 | KERN_ERR | |
181 | "%s: attach failed, can't connect to jpeg processor!\n", | |
182 | ptr->name); | |
183 | return -ENXIO; | |
184 | } | |
185 | zr36050_write(ptr, ZR050_SOF_IDX, 0xff); | |
186 | zr36050_write(ptr, ZR050_SOF_IDX + 1, 0xc0); | |
187 | if (((zr36050_read(ptr, ZR050_SOF_IDX) << 8) | | |
188 | zr36050_read(ptr, ZR050_SOF_IDX + 1)) != 0xffc0) { | |
189 | dprintk(1, | |
190 | KERN_ERR | |
191 | "%s: attach failed, can't connect to jpeg processor!\n", | |
192 | ptr->name); | |
193 | return -ENXIO; | |
194 | } | |
195 | ||
196 | zr36050_wait_end(ptr); | |
197 | if ((ptr->status1 & 0x4) == 0) { | |
198 | dprintk(1, | |
199 | KERN_ERR | |
200 | "%s: attach failed, jpeg processor failed (end flag)!\n", | |
201 | ptr->name); | |
202 | return -EBUSY; | |
203 | } | |
204 | ||
205 | return 0; /* looks good! */ | |
206 | } | |
207 | ||
208 | /* ========================================================================= | |
209 | Local helper function: | |
210 | ||
211 | simple loop for pushing the init datasets | |
212 | ========================================================================= */ | |
213 | ||
214 | static int | |
215 | zr36050_pushit (struct zr36050 *ptr, | |
d56410e0 MCC |
216 | u16 startreg, |
217 | u16 len, | |
218 | const char *data) | |
1da177e4 LT |
219 | { |
220 | int i = 0; | |
221 | ||
222 | dprintk(4, "%s: write data block to 0x%04x (len=%d)\n", ptr->name, | |
223 | startreg, len); | |
224 | while (i < len) { | |
225 | zr36050_write(ptr, startreg++, data[i++]); | |
226 | } | |
227 | ||
228 | return i; | |
229 | } | |
230 | ||
231 | /* ========================================================================= | |
232 | Basic datasets: | |
233 | ||
234 | jpeg baseline setup data (you find it on lots places in internet, or just | |
235 | extract it from any regular .jpg image...) | |
236 | ||
237 | Could be variable, but until it's not needed it they are just fixed to save | |
238 | memory. Otherwise expand zr36050 structure with arrays, push the values to | |
421f91d2 | 239 | it and initialize from there, as e.g. the linux zr36057/60 driver does it. |
1da177e4 LT |
240 | ========================================================================= */ |
241 | ||
242 | static const char zr36050_dqt[0x86] = { | |
243 | 0xff, 0xdb, //Marker: DQT | |
244 | 0x00, 0x84, //Length: 2*65+2 | |
245 | 0x00, //Pq,Tq first table | |
246 | 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, | |
247 | 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, | |
248 | 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, | |
249 | 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, | |
250 | 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44, | |
251 | 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, | |
252 | 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, | |
253 | 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, | |
254 | 0x01, //Pq,Tq second table | |
255 | 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, | |
256 | 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, | |
257 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, | |
258 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, | |
259 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, | |
260 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, | |
261 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, | |
262 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 | |
263 | }; | |
264 | ||
265 | static const char zr36050_dht[0x1a4] = { | |
266 | 0xff, 0xc4, //Marker: DHT | |
267 | 0x01, 0xa2, //Length: 2*AC, 2*DC | |
268 | 0x00, //DC first table | |
269 | 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, | |
270 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, | |
271 | 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, | |
272 | 0x01, //DC second table | |
273 | 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | |
274 | 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, | |
275 | 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, | |
276 | 0x10, //AC first table | |
277 | 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, | |
278 | 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, | |
279 | 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, | |
280 | 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, | |
281 | 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, | |
282 | 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, | |
283 | 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, | |
284 | 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, | |
285 | 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, | |
286 | 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, | |
287 | 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, | |
288 | 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, | |
289 | 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, | |
290 | 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, | |
291 | 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, | |
292 | 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, | |
293 | 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, | |
294 | 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, | |
295 | 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, | |
296 | 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, | |
297 | 0xF8, 0xF9, 0xFA, | |
298 | 0x11, //AC second table | |
299 | 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, | |
300 | 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, | |
301 | 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, | |
302 | 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, | |
303 | 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, | |
304 | 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, | |
305 | 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, | |
306 | 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, | |
307 | 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, | |
308 | 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, | |
309 | 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, | |
310 | 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, | |
311 | 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, | |
312 | 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, | |
313 | 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, | |
314 | 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, | |
315 | 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, | |
316 | 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, | |
317 | 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, | |
318 | 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, | |
319 | 0xF9, 0xFA | |
320 | }; | |
321 | ||
322 | /* jpeg baseline setup, this is just fixed in this driver (YUV pictures) */ | |
323 | #define NO_OF_COMPONENTS 0x3 //Y,U,V | |
324 | #define BASELINE_PRECISION 0x8 //MCU size (?) | |
325 | static const char zr36050_tq[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's QT | |
326 | static const char zr36050_td[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's DC | |
327 | static const char zr36050_ta[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's AC | |
328 | ||
329 | /* horizontal 422 decimation setup (maybe we support 411 or so later, too) */ | |
330 | static const char zr36050_decimation_h[8] = { 2, 1, 1, 0, 0, 0, 0, 0 }; | |
331 | static const char zr36050_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 }; | |
332 | ||
333 | /* ========================================================================= | |
334 | Local helper functions: | |
335 | ||
336 | calculation and setup of parameter-dependent JPEG baseline segments | |
337 | (needed for compression only) | |
338 | ========================================================================= */ | |
339 | ||
340 | /* ------------------------------------------------------------------------- */ | |
341 | ||
342 | /* SOF (start of frame) segment depends on width, height and sampling ratio | |
d56410e0 | 343 | of each color component */ |
1da177e4 LT |
344 | |
345 | static int | |
346 | zr36050_set_sof (struct zr36050 *ptr) | |
347 | { | |
348 | char sof_data[34]; // max. size of register set | |
349 | int i; | |
350 | ||
351 | dprintk(3, "%s: write SOF (%dx%d, %d components)\n", ptr->name, | |
352 | ptr->width, ptr->height, NO_OF_COMPONENTS); | |
353 | sof_data[0] = 0xff; | |
354 | sof_data[1] = 0xc0; | |
355 | sof_data[2] = 0x00; | |
356 | sof_data[3] = (3 * NO_OF_COMPONENTS) + 8; | |
357 | sof_data[4] = BASELINE_PRECISION; // only '8' possible with zr36050 | |
358 | sof_data[5] = (ptr->height) >> 8; | |
359 | sof_data[6] = (ptr->height) & 0xff; | |
360 | sof_data[7] = (ptr->width) >> 8; | |
361 | sof_data[8] = (ptr->width) & 0xff; | |
362 | sof_data[9] = NO_OF_COMPONENTS; | |
363 | for (i = 0; i < NO_OF_COMPONENTS; i++) { | |
364 | sof_data[10 + (i * 3)] = i; // index identifier | |
365 | sof_data[11 + (i * 3)] = (ptr->h_samp_ratio[i] << 4) | (ptr->v_samp_ratio[i]); // sampling ratios | |
366 | sof_data[12 + (i * 3)] = zr36050_tq[i]; // Q table selection | |
367 | } | |
368 | return zr36050_pushit(ptr, ZR050_SOF_IDX, | |
369 | (3 * NO_OF_COMPONENTS) + 10, sof_data); | |
370 | } | |
371 | ||
372 | /* ------------------------------------------------------------------------- */ | |
373 | ||
d56410e0 MCC |
374 | /* SOS (start of scan) segment depends on the used scan components |
375 | of each color component */ | |
1da177e4 LT |
376 | |
377 | static int | |
378 | zr36050_set_sos (struct zr36050 *ptr) | |
379 | { | |
380 | char sos_data[16]; // max. size of register set | |
381 | int i; | |
382 | ||
383 | dprintk(3, "%s: write SOS\n", ptr->name); | |
384 | sos_data[0] = 0xff; | |
385 | sos_data[1] = 0xda; | |
386 | sos_data[2] = 0x00; | |
387 | sos_data[3] = 2 + 1 + (2 * NO_OF_COMPONENTS) + 3; | |
388 | sos_data[4] = NO_OF_COMPONENTS; | |
389 | for (i = 0; i < NO_OF_COMPONENTS; i++) { | |
390 | sos_data[5 + (i * 2)] = i; // index | |
391 | sos_data[6 + (i * 2)] = (zr36050_td[i] << 4) | zr36050_ta[i]; // AC/DC tbl.sel. | |
392 | } | |
393 | sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 2] = 00; // scan start | |
394 | sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 3] = 0x3F; | |
395 | sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 4] = 00; | |
396 | return zr36050_pushit(ptr, ZR050_SOS1_IDX, | |
397 | 4 + 1 + (2 * NO_OF_COMPONENTS) + 3, | |
398 | sos_data); | |
399 | } | |
400 | ||
401 | /* ------------------------------------------------------------------------- */ | |
402 | ||
403 | /* DRI (define restart interval) */ | |
404 | ||
405 | static int | |
406 | zr36050_set_dri (struct zr36050 *ptr) | |
407 | { | |
408 | char dri_data[6]; // max. size of register set | |
409 | ||
410 | dprintk(3, "%s: write DRI\n", ptr->name); | |
411 | dri_data[0] = 0xff; | |
412 | dri_data[1] = 0xdd; | |
413 | dri_data[2] = 0x00; | |
414 | dri_data[3] = 0x04; | |
415 | dri_data[4] = ptr->dri >> 8; | |
416 | dri_data[5] = ptr->dri & 0xff; | |
417 | return zr36050_pushit(ptr, ZR050_DRI_IDX, 6, dri_data); | |
418 | } | |
419 | ||
420 | /* ========================================================================= | |
421 | Setup function: | |
422 | ||
423 | Setup compression/decompression of Zoran's JPEG processor | |
424 | ( see also zoran 36050 manual ) | |
425 | ||
426 | ... sorry for the spaghetti code ... | |
427 | ========================================================================= */ | |
428 | static void | |
429 | zr36050_init (struct zr36050 *ptr) | |
430 | { | |
431 | int sum = 0; | |
432 | long bitcnt, tmp; | |
433 | ||
434 | if (ptr->mode == CODEC_DO_COMPRESSION) { | |
435 | dprintk(2, "%s: COMPRESSION SETUP\n", ptr->name); | |
436 | ||
437 | /* 050 communicates with 057 in master mode */ | |
438 | zr36050_write(ptr, ZR050_HARDWARE, ZR050_HW_MSTR); | |
439 | ||
440 | /* encoding table preload for compression */ | |
441 | zr36050_write(ptr, ZR050_MODE, | |
442 | ZR050_MO_COMP | ZR050_MO_TLM); | |
443 | zr36050_write(ptr, ZR050_OPTIONS, 0); | |
444 | ||
445 | /* disable all IRQs */ | |
446 | zr36050_write(ptr, ZR050_INT_REQ_0, 0); | |
447 | zr36050_write(ptr, ZR050_INT_REQ_1, 3); // low 2 bits always 1 | |
448 | ||
449 | /* volume control settings */ | |
450 | /*zr36050_write(ptr, ZR050_MBCV, ptr->max_block_vol);*/ | |
451 | zr36050_write(ptr, ZR050_SF_HI, ptr->scalefact >> 8); | |
452 | zr36050_write(ptr, ZR050_SF_LO, ptr->scalefact & 0xff); | |
453 | ||
454 | zr36050_write(ptr, ZR050_AF_HI, 0xff); | |
455 | zr36050_write(ptr, ZR050_AF_M, 0xff); | |
456 | zr36050_write(ptr, ZR050_AF_LO, 0xff); | |
457 | ||
458 | /* setup the variable jpeg tables */ | |
459 | sum += zr36050_set_sof(ptr); | |
460 | sum += zr36050_set_sos(ptr); | |
461 | sum += zr36050_set_dri(ptr); | |
462 | ||
463 | /* setup the fixed jpeg tables - maybe variable, though - | |
464 | * (see table init section above) */ | |
465 | dprintk(3, "%s: write DQT, DHT, APP\n", ptr->name); | |
466 | sum += zr36050_pushit(ptr, ZR050_DQT_IDX, | |
467 | sizeof(zr36050_dqt), zr36050_dqt); | |
468 | sum += zr36050_pushit(ptr, ZR050_DHT_IDX, | |
469 | sizeof(zr36050_dht), zr36050_dht); | |
470 | zr36050_write(ptr, ZR050_APP_IDX, 0xff); | |
471 | zr36050_write(ptr, ZR050_APP_IDX + 1, 0xe0 + ptr->app.appn); | |
472 | zr36050_write(ptr, ZR050_APP_IDX + 2, 0x00); | |
473 | zr36050_write(ptr, ZR050_APP_IDX + 3, ptr->app.len + 2); | |
474 | sum += zr36050_pushit(ptr, ZR050_APP_IDX + 4, 60, | |
475 | ptr->app.data) + 4; | |
476 | zr36050_write(ptr, ZR050_COM_IDX, 0xff); | |
477 | zr36050_write(ptr, ZR050_COM_IDX + 1, 0xfe); | |
478 | zr36050_write(ptr, ZR050_COM_IDX + 2, 0x00); | |
479 | zr36050_write(ptr, ZR050_COM_IDX + 3, ptr->com.len + 2); | |
480 | sum += zr36050_pushit(ptr, ZR050_COM_IDX + 4, 60, | |
481 | ptr->com.data) + 4; | |
482 | ||
483 | /* do the internal huffman table preload */ | |
484 | zr36050_write(ptr, ZR050_MARKERS_EN, ZR050_ME_DHTI); | |
485 | ||
486 | zr36050_write(ptr, ZR050_GO, 1); // launch codec | |
487 | zr36050_wait_end(ptr); | |
488 | dprintk(2, "%s: Status after table preload: 0x%02x\n", | |
489 | ptr->name, ptr->status1); | |
490 | ||
491 | if ((ptr->status1 & 0x4) == 0) { | |
492 | dprintk(1, KERN_ERR "%s: init aborted!\n", | |
493 | ptr->name); | |
494 | return; // something is wrong, its timed out!!!! | |
495 | } | |
496 | ||
497 | /* setup misc. data for compression (target code sizes) */ | |
498 | ||
499 | /* size of compressed code to reach without header data */ | |
500 | sum = ptr->real_code_vol - sum; | |
501 | bitcnt = sum << 3; /* need the size in bits */ | |
502 | ||
503 | tmp = bitcnt >> 16; | |
504 | dprintk(3, | |
505 | "%s: code: csize=%d, tot=%d, bit=%ld, highbits=%ld\n", | |
506 | ptr->name, sum, ptr->real_code_vol, bitcnt, tmp); | |
507 | zr36050_write(ptr, ZR050_TCV_NET_HI, tmp >> 8); | |
508 | zr36050_write(ptr, ZR050_TCV_NET_MH, tmp & 0xff); | |
509 | tmp = bitcnt & 0xffff; | |
510 | zr36050_write(ptr, ZR050_TCV_NET_ML, tmp >> 8); | |
511 | zr36050_write(ptr, ZR050_TCV_NET_LO, tmp & 0xff); | |
512 | ||
513 | bitcnt -= bitcnt >> 7; // bits without stuffing | |
514 | bitcnt -= ((bitcnt * 5) >> 6); // bits without eob | |
515 | ||
516 | tmp = bitcnt >> 16; | |
517 | dprintk(3, "%s: code: nettobit=%ld, highnettobits=%ld\n", | |
518 | ptr->name, bitcnt, tmp); | |
519 | zr36050_write(ptr, ZR050_TCV_DATA_HI, tmp >> 8); | |
520 | zr36050_write(ptr, ZR050_TCV_DATA_MH, tmp & 0xff); | |
521 | tmp = bitcnt & 0xffff; | |
522 | zr36050_write(ptr, ZR050_TCV_DATA_ML, tmp >> 8); | |
523 | zr36050_write(ptr, ZR050_TCV_DATA_LO, tmp & 0xff); | |
524 | ||
525 | /* compression setup with or without bitrate control */ | |
526 | zr36050_write(ptr, ZR050_MODE, | |
527 | ZR050_MO_COMP | ZR050_MO_PASS2 | | |
528 | (ptr->bitrate_ctrl ? ZR050_MO_BRC : 0)); | |
529 | ||
530 | /* this headers seem to deliver "valid AVI" jpeg frames */ | |
531 | zr36050_write(ptr, ZR050_MARKERS_EN, | |
532 | ZR050_ME_DQT | ZR050_ME_DHT | | |
533 | ((ptr->app.len > 0) ? ZR050_ME_APP : 0) | | |
534 | ((ptr->com.len > 0) ? ZR050_ME_COM : 0)); | |
535 | } else { | |
536 | dprintk(2, "%s: EXPANSION SETUP\n", ptr->name); | |
537 | ||
538 | /* 050 communicates with 055 in master mode */ | |
539 | zr36050_write(ptr, ZR050_HARDWARE, | |
540 | ZR050_HW_MSTR | ZR050_HW_CFIS_2_CLK); | |
541 | ||
542 | /* encoding table preload */ | |
543 | zr36050_write(ptr, ZR050_MODE, ZR050_MO_TLM); | |
544 | ||
545 | /* disable all IRQs */ | |
546 | zr36050_write(ptr, ZR050_INT_REQ_0, 0); | |
547 | zr36050_write(ptr, ZR050_INT_REQ_1, 3); // low 2 bits always 1 | |
548 | ||
549 | dprintk(3, "%s: write DHT\n", ptr->name); | |
550 | zr36050_pushit(ptr, ZR050_DHT_IDX, sizeof(zr36050_dht), | |
551 | zr36050_dht); | |
552 | ||
553 | /* do the internal huffman table preload */ | |
554 | zr36050_write(ptr, ZR050_MARKERS_EN, ZR050_ME_DHTI); | |
555 | ||
556 | zr36050_write(ptr, ZR050_GO, 1); // launch codec | |
557 | zr36050_wait_end(ptr); | |
558 | dprintk(2, "%s: Status after table preload: 0x%02x\n", | |
559 | ptr->name, ptr->status1); | |
560 | ||
561 | if ((ptr->status1 & 0x4) == 0) { | |
562 | dprintk(1, KERN_ERR "%s: init aborted!\n", | |
563 | ptr->name); | |
564 | return; // something is wrong, its timed out!!!! | |
565 | } | |
566 | ||
567 | /* setup misc. data for expansion */ | |
568 | zr36050_write(ptr, ZR050_MODE, 0); | |
569 | zr36050_write(ptr, ZR050_MARKERS_EN, 0); | |
570 | } | |
571 | ||
572 | /* adr on selected, to allow GO from master */ | |
573 | zr36050_read(ptr, 0); | |
574 | } | |
575 | ||
576 | /* ========================================================================= | |
577 | CODEC API FUNCTIONS | |
578 | ||
579 | this functions are accessed by the master via the API structure | |
580 | ========================================================================= */ | |
581 | ||
582 | /* set compression/expansion mode and launches codec - | |
583 | this should be the last call from the master before starting processing */ | |
584 | static int | |
585 | zr36050_set_mode (struct videocodec *codec, | |
586 | int mode) | |
587 | { | |
588 | struct zr36050 *ptr = (struct zr36050 *) codec->data; | |
589 | ||
590 | dprintk(2, "%s: set_mode %d call\n", ptr->name, mode); | |
591 | ||
592 | if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION)) | |
593 | return -EINVAL; | |
594 | ||
595 | ptr->mode = mode; | |
596 | zr36050_init(ptr); | |
597 | ||
598 | return 0; | |
599 | } | |
600 | ||
601 | /* set picture size (norm is ignored as the codec doesn't know about it) */ | |
602 | static int | |
603 | zr36050_set_video (struct videocodec *codec, | |
604 | struct tvnorm *norm, | |
605 | struct vfe_settings *cap, | |
606 | struct vfe_polarity *pol) | |
607 | { | |
608 | struct zr36050 *ptr = (struct zr36050 *) codec->data; | |
609 | int size; | |
610 | ||
611 | dprintk(2, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) q%d call\n", | |
612 | ptr->name, norm->HStart, norm->VStart, | |
613 | cap->x, cap->y, cap->width, cap->height, | |
614 | cap->decimation, cap->quality); | |
615 | /* if () return -EINVAL; | |
616 | * trust the master driver that it knows what it does - so | |
617 | * we allow invalid startx/y and norm for now ... */ | |
618 | ptr->width = cap->width / (cap->decimation & 0xff); | |
619 | ptr->height = cap->height / ((cap->decimation >> 8) & 0xff); | |
620 | ||
621 | /* (KM) JPEG quality */ | |
622 | size = ptr->width * ptr->height; | |
623 | size *= 16; /* size in bits */ | |
624 | /* apply quality setting */ | |
625 | size = size * cap->quality / 200; | |
626 | ||
627 | /* Minimum: 1kb */ | |
628 | if (size < 8192) | |
629 | size = 8192; | |
630 | /* Maximum: 7/8 of code buffer */ | |
631 | if (size > ptr->total_code_vol * 7) | |
632 | size = ptr->total_code_vol * 7; | |
633 | ||
634 | ptr->real_code_vol = size >> 3; /* in bytes */ | |
635 | ||
636 | /* Set max_block_vol here (previously in zr36050_init, moved | |
637 | * here for consistency with zr36060 code */ | |
638 | zr36050_write(ptr, ZR050_MBCV, ptr->max_block_vol); | |
639 | ||
640 | return 0; | |
641 | } | |
642 | ||
643 | /* additional control functions */ | |
644 | static int | |
645 | zr36050_control (struct videocodec *codec, | |
646 | int type, | |
647 | int size, | |
648 | void *data) | |
649 | { | |
650 | struct zr36050 *ptr = (struct zr36050 *) codec->data; | |
651 | int *ival = (int *) data; | |
652 | ||
653 | dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type, | |
654 | size); | |
655 | ||
656 | switch (type) { | |
657 | case CODEC_G_STATUS: /* get last status */ | |
658 | if (size != sizeof(int)) | |
659 | return -EFAULT; | |
660 | zr36050_read_status1(ptr); | |
661 | *ival = ptr->status1; | |
662 | break; | |
663 | ||
664 | case CODEC_G_CODEC_MODE: | |
665 | if (size != sizeof(int)) | |
666 | return -EFAULT; | |
667 | *ival = CODEC_MODE_BJPG; | |
668 | break; | |
669 | ||
670 | case CODEC_S_CODEC_MODE: | |
671 | if (size != sizeof(int)) | |
672 | return -EFAULT; | |
673 | if (*ival != CODEC_MODE_BJPG) | |
674 | return -EINVAL; | |
675 | /* not needed, do nothing */ | |
676 | return 0; | |
677 | ||
678 | case CODEC_G_VFE: | |
679 | case CODEC_S_VFE: | |
680 | /* not needed, do nothing */ | |
681 | return 0; | |
682 | ||
683 | case CODEC_S_MMAP: | |
684 | /* not available, give an error */ | |
685 | return -ENXIO; | |
686 | ||
687 | case CODEC_G_JPEG_TDS_BYTE: /* get target volume in byte */ | |
688 | if (size != sizeof(int)) | |
689 | return -EFAULT; | |
690 | *ival = ptr->total_code_vol; | |
691 | break; | |
692 | ||
693 | case CODEC_S_JPEG_TDS_BYTE: /* get target volume in byte */ | |
694 | if (size != sizeof(int)) | |
695 | return -EFAULT; | |
696 | ptr->total_code_vol = *ival; | |
697 | /* (Kieran Morrissey) | |
698 | * code copied from zr36060.c to ensure proper bitrate */ | |
699 | ptr->real_code_vol = (ptr->total_code_vol * 6) >> 3; | |
700 | break; | |
701 | ||
702 | case CODEC_G_JPEG_SCALE: /* get scaling factor */ | |
703 | if (size != sizeof(int)) | |
704 | return -EFAULT; | |
705 | *ival = zr36050_read_scalefactor(ptr); | |
706 | break; | |
707 | ||
708 | case CODEC_S_JPEG_SCALE: /* set scaling factor */ | |
709 | if (size != sizeof(int)) | |
710 | return -EFAULT; | |
711 | ptr->scalefact = *ival; | |
712 | break; | |
713 | ||
714 | case CODEC_G_JPEG_APP_DATA: { /* get appn marker data */ | |
715 | struct jpeg_app_marker *app = data; | |
716 | ||
717 | if (size != sizeof(struct jpeg_app_marker)) | |
718 | return -EFAULT; | |
719 | ||
720 | *app = ptr->app; | |
721 | break; | |
722 | } | |
723 | ||
724 | case CODEC_S_JPEG_APP_DATA: { /* set appn marker data */ | |
725 | struct jpeg_app_marker *app = data; | |
726 | ||
727 | if (size != sizeof(struct jpeg_app_marker)) | |
728 | return -EFAULT; | |
729 | ||
730 | ptr->app = *app; | |
731 | break; | |
732 | } | |
733 | ||
734 | case CODEC_G_JPEG_COM_DATA: { /* get comment marker data */ | |
735 | struct jpeg_com_marker *com = data; | |
736 | ||
737 | if (size != sizeof(struct jpeg_com_marker)) | |
738 | return -EFAULT; | |
739 | ||
740 | *com = ptr->com; | |
741 | break; | |
742 | } | |
743 | ||
744 | case CODEC_S_JPEG_COM_DATA: { /* set comment marker data */ | |
745 | struct jpeg_com_marker *com = data; | |
746 | ||
747 | if (size != sizeof(struct jpeg_com_marker)) | |
748 | return -EFAULT; | |
749 | ||
750 | ptr->com = *com; | |
751 | break; | |
752 | } | |
753 | ||
754 | default: | |
755 | return -EINVAL; | |
756 | } | |
757 | ||
758 | return size; | |
759 | } | |
760 | ||
761 | /* ========================================================================= | |
762 | Exit and unregister function: | |
763 | ||
764 | Deinitializes Zoran's JPEG processor | |
765 | ========================================================================= */ | |
766 | ||
767 | static int | |
768 | zr36050_unset (struct videocodec *codec) | |
769 | { | |
770 | struct zr36050 *ptr = codec->data; | |
771 | ||
772 | if (ptr) { | |
773 | /* do wee need some codec deinit here, too ???? */ | |
774 | ||
775 | dprintk(1, "%s: finished codec #%d\n", ptr->name, | |
776 | ptr->num); | |
777 | kfree(ptr); | |
778 | codec->data = NULL; | |
779 | ||
780 | zr36050_codecs--; | |
781 | return 0; | |
782 | } | |
783 | ||
784 | return -EFAULT; | |
785 | } | |
786 | ||
787 | /* ========================================================================= | |
788 | Setup and registry function: | |
789 | ||
790 | Initializes Zoran's JPEG processor | |
791 | ||
792 | Also sets pixel size, average code size, mode (compr./decompr.) | |
793 | (the given size is determined by the processor with the video interface) | |
794 | ========================================================================= */ | |
795 | ||
796 | static int | |
797 | zr36050_setup (struct videocodec *codec) | |
798 | { | |
799 | struct zr36050 *ptr; | |
800 | int res; | |
801 | ||
802 | dprintk(2, "zr36050: initializing MJPEG subsystem #%d.\n", | |
803 | zr36050_codecs); | |
804 | ||
805 | if (zr36050_codecs == MAX_CODECS) { | |
806 | dprintk(1, | |
807 | KERN_ERR "zr36050: Can't attach more codecs!\n"); | |
808 | return -ENOSPC; | |
809 | } | |
810 | //mem structure init | |
7408187d | 811 | codec->data = ptr = kzalloc(sizeof(struct zr36050), GFP_KERNEL); |
1da177e4 LT |
812 | if (NULL == ptr) { |
813 | dprintk(1, KERN_ERR "zr36050: Can't get enough memory!\n"); | |
814 | return -ENOMEM; | |
815 | } | |
1da177e4 LT |
816 | |
817 | snprintf(ptr->name, sizeof(ptr->name), "zr36050[%d]", | |
818 | zr36050_codecs); | |
819 | ptr->num = zr36050_codecs++; | |
820 | ptr->codec = codec; | |
821 | ||
822 | //testing | |
823 | res = zr36050_basic_test(ptr); | |
824 | if (res < 0) { | |
825 | zr36050_unset(codec); | |
826 | return res; | |
827 | } | |
828 | //final setup | |
829 | memcpy(ptr->h_samp_ratio, zr36050_decimation_h, 8); | |
830 | memcpy(ptr->v_samp_ratio, zr36050_decimation_v, 8); | |
831 | ||
832 | ptr->bitrate_ctrl = 0; /* 0 or 1 - fixed file size flag | |
833 | * (what is the difference?) */ | |
834 | ptr->mode = CODEC_DO_COMPRESSION; | |
835 | ptr->width = 384; | |
836 | ptr->height = 288; | |
837 | ptr->total_code_vol = 16000; | |
838 | ptr->max_block_vol = 240; | |
839 | ptr->scalefact = 0x100; | |
840 | ptr->dri = 1; | |
841 | ||
842 | /* no app/com marker by default */ | |
843 | ptr->app.appn = 0; | |
844 | ptr->app.len = 0; | |
845 | ptr->com.len = 0; | |
846 | ||
847 | zr36050_init(ptr); | |
848 | ||
849 | dprintk(1, KERN_INFO "%s: codec attached and running\n", | |
850 | ptr->name); | |
851 | ||
852 | return 0; | |
853 | } | |
854 | ||
855 | static const struct videocodec zr36050_codec = { | |
856 | .owner = THIS_MODULE, | |
857 | .name = "zr36050", | |
858 | .magic = 0L, // magic not used | |
859 | .flags = | |
860 | CODEC_FLAG_JPEG | CODEC_FLAG_HARDWARE | CODEC_FLAG_ENCODER | | |
861 | CODEC_FLAG_DECODER, | |
862 | .type = CODEC_TYPE_ZR36050, | |
863 | .setup = zr36050_setup, // functionality | |
864 | .unset = zr36050_unset, | |
865 | .set_mode = zr36050_set_mode, | |
866 | .set_video = zr36050_set_video, | |
867 | .control = zr36050_control, | |
868 | // others are not used | |
869 | }; | |
870 | ||
871 | /* ========================================================================= | |
872 | HOOK IN DRIVER AS KERNEL MODULE | |
873 | ========================================================================= */ | |
874 | ||
875 | static int __init | |
876 | zr36050_init_module (void) | |
877 | { | |
878 | //dprintk(1, "ZR36050 driver %s\n",ZR050_VERSION); | |
879 | zr36050_codecs = 0; | |
880 | return videocodec_register(&zr36050_codec); | |
881 | } | |
882 | ||
883 | static void __exit | |
884 | zr36050_cleanup_module (void) | |
885 | { | |
886 | if (zr36050_codecs) { | |
887 | dprintk(1, | |
888 | "zr36050: something's wrong - %d codecs left somehow.\n", | |
889 | zr36050_codecs); | |
890 | } | |
891 | videocodec_unregister(&zr36050_codec); | |
892 | } | |
893 | ||
894 | module_init(zr36050_init_module); | |
895 | module_exit(zr36050_cleanup_module); | |
896 | ||
897 | MODULE_AUTHOR("Wolfgang Scherr <scherr@net4you.at>"); | |
898 | MODULE_DESCRIPTION("Driver module for ZR36050 jpeg processors " | |
899 | ZR050_VERSION); | |
900 | MODULE_LICENSE("GPL"); |